8dfe106713d396c9fcf45b0787d2fdf2e24e6fcf
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / csar / ServiceCsarInfo.java
1 /*
2  * -
3  *  ============LICENSE_START=======================================================
4  *  Copyright (C) 2022 Nordix Foundation.
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.sdc.be.components.csar;
23
24 import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.DEFAULT_ICON;
25 import static org.openecomp.sdc.be.components.impl.ImportUtils.findToscaElement;
26
27 import fj.data.Either;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import org.apache.commons.collections.CollectionUtils;
39 import org.apache.commons.collections.MapUtils;
40 import org.openecomp.sdc.be.components.impl.ImportUtils;
41 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
42 import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum;
43 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
44 import org.openecomp.sdc.be.model.NodeTypeDefinition;
45 import org.openecomp.sdc.be.model.NodeTypeInfo;
46 import org.openecomp.sdc.be.model.NodeTypeMetadata;
47 import org.openecomp.sdc.be.model.User;
48 import org.openecomp.sdc.be.model.category.CategoryDefinition;
49 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
50 import org.openecomp.sdc.be.utils.TypeUtils;
51 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
52 import org.openecomp.sdc.common.log.wrappers.Logger;
53 import org.yaml.snakeyaml.Yaml;
54
55 /**
56  * Provides access to the contents of a Service CSAR
57  */
58 public class ServiceCsarInfo extends CsarInfo {
59
60     private static final Logger log = Logger.getLogger(ServiceCsarInfo.class);
61     private final Map<String, Map<String, Object>> mainTemplateImports;
62     private List<NodeTypeDefinition> nodeTypeDefinitions;
63
64     public ServiceCsarInfo(final User modifier, final String csarUUID, final Map<String, byte[]> csar, final String vfResourceName,
65                            final String mainTemplateName, final String mainTemplateContent, final boolean isUpdate) {
66         super(modifier, csarUUID, csar, vfResourceName, mainTemplateName, mainTemplateContent, isUpdate);
67
68         final Path mainTemplateDir = Paths.get(getMainTemplateName().substring(0, getMainTemplateName().lastIndexOf('/') + 1));
69         final Collection<Path> filesHandled = new HashSet<>();
70         filesHandled.add(Paths.get(mainTemplateName));
71         this.mainTemplateImports = getTemplateImports(csar, new Yaml().load(mainTemplateContent), mainTemplateDir, filesHandled);
72     }
73
74     private Map<String, Map<String, Object>> getTemplateImports(final Map<String, byte[]> csar, Map<String, Object> mappedToscaMainTemplate,
75                                                                 final Path fileParentDir, final Collection<Path> filesHandled) {
76         final Map<String, Map<String, Object>> templateImports = new HashMap<>();
77
78         final List<Path> importFilePaths = getTemplateImportFilePaths(mappedToscaMainTemplate, fileParentDir);
79
80         importFilePaths.stream().filter(path -> !filesHandled.contains(path)).forEach(
81                 importFilePath -> {
82                     byte[] importFile = csar.get(importFilePath.toString());
83                     if (importFile != null) {
84                         filesHandled.add(importFilePath);
85                         Map<String, Object> mappedImportFile = new Yaml().load(new String(csar.get(importFilePath.toString())));
86                         templateImports.put(importFilePath.toString(), mappedImportFile);
87                         templateImports.putAll(getTemplateImports(csar, mappedImportFile, importFilePath.getParent(), filesHandled));
88                     } else {
89                         log.info("Import {} cannot be found in CSAR", importFilePath.toString());
90                     }
91                 });
92
93         return templateImports;
94     }
95
96     @SuppressWarnings({"unchecked", "rawtypes"})
97     private List<Path> getTemplateImportFilePaths(final Map<String, Object> mappedToscaTemplate, final Path fileParentDir) {
98         final Either<Object, ResultStatusEnum> importsEither =
99             findToscaElement(mappedToscaTemplate, ToscaTagNamesEnum.IMPORTS, ToscaElementTypeEnum.ALL);
100
101         if (importsEither.isLeft()) {
102             final List importsList = (List) importsEither.left().value();
103             if (CollectionUtils.isNotEmpty(importsList)) {
104                 if (importsList.get(0) instanceof String) {
105                     List<Path> importPaths = new ArrayList<>();
106                     importsList.stream().forEach(importPath -> importPaths.add(Paths.get((String) importPath)));
107                     return importPaths;
108                 } else if (importsList.get(0) instanceof Map) {
109                     return getTemplateImportFilePathsMultiLineGrammar(importsList, fileParentDir);
110                 }
111             }
112
113         }
114         return Collections.emptyList();
115     }
116
117     @SuppressWarnings("unchecked")
118     private List<Path> getTemplateImportFilePathsMultiLineGrammar(final List<Map<String, Object>> importsList, final Path fileParentDir) {
119         final List<Path> importFiles = new ArrayList<>();
120
121         for (Map<String, Object> importFileMultiLineGrammar : importsList) {
122             if (MapUtils.isNotEmpty(importFileMultiLineGrammar)) {
123                 if (importFileMultiLineGrammar.values().iterator().next() instanceof String) {
124                     Path relativePath = Paths.get((String) importFileMultiLineGrammar.get("file"));
125                     Path absolutePath = fileParentDir == null ? relativePath : fileParentDir.resolve(relativePath).normalize();
126                     importFiles.add(absolutePath);
127                 } else if (importFileMultiLineGrammar.values().iterator().next() instanceof Map) {
128                     importFileMultiLineGrammar.values().forEach(value -> {
129                         Path relativePath = Paths.get((String) ((Map<String, Object>) value).get("file"));
130                         Path absolutePath = fileParentDir == null ? relativePath : fileParentDir.resolve(relativePath).normalize();
131                         importFiles.add(absolutePath);
132                     });
133                 }
134             }
135         }
136         return importFiles;
137     }
138
139     @Override
140     public Map<String, NodeTypeInfo> extractTypesInfo() {
141         return Collections.emptyMap();
142     }
143
144     @Override
145     public Map<String, Object> getDataTypes() {
146         final Map<String, Object> definitions = new HashMap<>();
147         mainTemplateImports.entrySet().stream()
148             .forEach(entry -> definitions.putAll(getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.DATA_TYPES)));
149         definitions.putAll(getTypesFromTemplate(getMappedToscaMainTemplate(), TypeUtils.ToscaTagNamesEnum.DATA_TYPES));
150         return definitions;
151     }
152
153     public List<NodeTypeDefinition> getNodeTypesUsed() {
154         if (nodeTypeDefinitions == null) {
155             nodeTypeDefinitions = new ArrayList<>();
156             final Set<String> nodeTypesUsed = getNodeTypesUsedInToscaTemplate(getMappedToscaMainTemplate());
157             nodeTypeDefinitions.addAll(getNodeTypeDefinitions(nodeTypesUsed));
158         }
159         nodeTypeDefinitions = sortNodeTypesByDependencyOrder(nodeTypeDefinitions);
160         return nodeTypeDefinitions;
161     }
162
163     private List<NodeTypeDefinition> sortNodeTypesByDependencyOrder(final List<NodeTypeDefinition> nodeTypes) {
164         final List<NodeTypeDefinition> sortedNodeTypeDefinitions = new ArrayList<>();
165         final Map<String, NodeTypeDefinition> nodeTypeDefinitionsMap = new HashMap<>();
166
167         nodeTypes.forEach(nodeType -> {
168             int highestDependencyIndex = -1;
169             for (final String dependencyName : getDependencyTypes(nodeType, nodeTypes)) {
170                 final NodeTypeDefinition dependency = nodeTypeDefinitionsMap.get(dependencyName);
171                 final int indexOfDependency = sortedNodeTypeDefinitions.lastIndexOf(dependency);
172                 highestDependencyIndex = indexOfDependency > highestDependencyIndex ? indexOfDependency : highestDependencyIndex;
173             }
174             sortedNodeTypeDefinitions.add(highestDependencyIndex + 1, nodeType);
175             nodeTypeDefinitionsMap.put(nodeType.getNodeTypeMetadata().getToscaName(), nodeType);
176         });
177         return sortedNodeTypeDefinitions;
178     }
179
180     private Collection<String> getDependencyTypes(final NodeTypeDefinition nodeType, final List<NodeTypeDefinition> nodeTypes) {
181         final Set<String> dependencies = new HashSet<>();
182         Either<Object, ResultStatusEnum> derivedFromTypeEither = findToscaElement((Map<String, Object>) nodeType.getMappedNodeType().getValue(),
183             TypeUtils.ToscaTagNamesEnum.DERIVED_FROM, ToscaElementTypeEnum.STRING);
184         if (derivedFromTypeEither.isLeft() && derivedFromTypeEither.left().value() != null) {
185             final String derivedFrom = (String) derivedFromTypeEither.left().value();
186             dependencies.add(derivedFrom);
187             nodeTypes.stream().filter(derivedFromCandidate -> derivedFrom.contentEquals(derivedFromCandidate.getNodeTypeMetadata().getToscaName()))
188                 .forEach(derivedFromNodeType -> dependencies.addAll(getDependencyTypes(derivedFromNodeType, nodeTypes)));
189         }
190         return dependencies;
191     }
192
193     private Set<NodeTypeDefinition> getNodeTypeDefinitions(final Set<String> nodeTypesToGet) {
194         final Set<NodeTypeDefinition> nodeTypesToReturn = new HashSet<>();
195         final Set<NodeTypeDefinition> foundNodeTypes = getTypes(nodeTypesToGet);
196         nodeTypesToReturn.addAll(foundNodeTypes);
197         final Set<String> recursiveNodeTypesToGet = new HashSet<>();
198         foundNodeTypes.stream().forEach(nodeTypeDef -> {
199             Either<Object, ResultStatusEnum> derivedFromTypeEither =
200                 findToscaElement((Map<String, Object>) nodeTypeDef.getMappedNodeType().getValue(), TypeUtils.ToscaTagNamesEnum.DERIVED_FROM,
201                     ToscaElementTypeEnum.STRING);
202             if (derivedFromTypeEither.isLeft()) {
203                 recursiveNodeTypesToGet.add((String)derivedFromTypeEither.left().value());
204             }
205         });
206         recursiveNodeTypesToGet.removeAll(nodeTypesToGet);
207         if (CollectionUtils.isNotEmpty(recursiveNodeTypesToGet)) {
208             nodeTypesToReturn.addAll(getNodeTypeDefinitions(recursiveNodeTypesToGet));
209         }
210         return nodeTypesToReturn;
211     }
212
213
214     private Set<NodeTypeDefinition> getTypes(final Set<String> nodeTypes) {
215         Set<NodeTypeDefinition> nodeTypeDefinitionsLocal = new HashSet<>();
216         mainTemplateImports.entrySet().forEach(entry -> {
217             final Map<String, Object> types = getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.NODE_TYPES, nodeTypes);
218             if (MapUtils.isNotEmpty(types)) {
219                 types.entrySet().stream().forEach(typesEntry -> {
220                     final NodeTypeMetadata metadata =
221                         getMetaDataFromTemplate(entry.getValue(), typesEntry.getKey());
222                     nodeTypeDefinitionsLocal.add(new NodeTypeDefinition(typesEntry, metadata));
223                 });
224             }
225         });
226         return nodeTypeDefinitionsLocal;
227     }
228
229     @SuppressWarnings("unchecked")
230     private Set<String> getNodeTypesUsedInToscaTemplate(Map<String, Object> mappedToscaTemplate) {
231         final Either<Object, ResultStatusEnum> nodeTemplatesEither = findToscaElement(mappedToscaTemplate,
232             TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES, ToscaElementTypeEnum.MAP);
233         final Set<String> nodeTypesUsedInNodeTemplates = new HashSet<>();
234         if (nodeTemplatesEither.isLeft()) {
235             final Map<String, Map<String, Object>> nodeTemplates =
236                 (Map<String, Map<String, Object>>) nodeTemplatesEither.left().value();
237             nodeTypesUsedInNodeTemplates.addAll(findNodeTypesUsedInNodeTemplates(nodeTemplates));
238         }
239         return nodeTypesUsedInNodeTemplates;
240     }
241
242     private NodeTypeMetadata getMetaDataFromTemplate(Map<String, Object> mappedResourceTemplate, String nodeTemplateType) {
243         NodeTypeMetadata nodeTypeMetadata = new NodeTypeMetadata();
244         Either<Map<String, Object>, ImportUtils.ResultStatusEnum> metadataEither = ImportUtils.findFirstToscaMapElement(mappedResourceTemplate, TypeUtils.ToscaTagNamesEnum.METADATA);
245         if (metadataEither.isLeft() && metadataEither.left().value().get("type").equals(ResourceTypeEnum.VFC.getValue())) {
246             Map<String, Object> metadata = metadataEither.left().value();
247             createMetadataFromTemplate(nodeTypeMetadata, metadata, nodeTemplateType);
248         } else {
249             createDefaultMetadata(nodeTypeMetadata, nodeTemplateType);
250         }
251         return nodeTypeMetadata;
252     }
253
254     private void createMetadataFromTemplate(NodeTypeMetadata nodeTypeMetadata,  Map<String, Object> metadata, String nodeTemplateType) {
255         nodeTypeMetadata.setToscaName(nodeTemplateType);
256         nodeTypeMetadata.setContactId(getModifier().getUserId());
257         nodeTypeMetadata.setDescription((String) metadata.get("description"));
258         List<String> tags = new ArrayList<>();
259         tags.add((String) metadata.get("name"));
260         nodeTypeMetadata.setTags(tags);
261         SubCategoryDefinition subCategory = new SubCategoryDefinition();
262         subCategory.setName((String) metadata.get("subcategory"));
263         CategoryDefinition category = new CategoryDefinition();
264         category.setName((String) metadata.get("category"));
265         category.setNormalizedName(((String) metadata.get("category")).toLowerCase());
266         category.setIcons(List.of(DEFAULT_ICON));
267         category.setNormalizedName(((String) metadata.get("category")).toLowerCase());
268         category.addSubCategory(subCategory);
269         List<CategoryDefinition> categories = new ArrayList<>();
270         categories.add(category);
271         nodeTypeMetadata.setCategories(categories);
272         nodeTypeMetadata.setName((String) metadata.get("name"));
273         nodeTypeMetadata.setIcon("defaulticon");
274         nodeTypeMetadata.setResourceVendorModelNumber((String) metadata.get("resourceVendorModelNumber"));
275         nodeTypeMetadata.setResourceType((String) metadata.get("type"));
276         nodeTypeMetadata.setVendorName((String) metadata.get("resourceVendor"));
277         nodeTypeMetadata.setVendorRelease((String) metadata.get("resourceVendorRelease"));
278         nodeTypeMetadata.setModel((String) metadata.get("model"));
279         nodeTypeMetadata.setNormative(false);
280     }
281
282     private void createDefaultMetadata(NodeTypeMetadata nodeTypeMetadata, String nodeTemplateType) {
283         nodeTypeMetadata.setToscaName(nodeTemplateType);
284         nodeTypeMetadata.setContactId(getModifier().getUserId());
285         nodeTypeMetadata.setDescription("A vfc of type " + nodeTemplateType);
286         Either<Map<String, Object>, ResultStatusEnum> mainMetadataEither = ImportUtils.findFirstToscaMapElement(getMappedToscaMainTemplate(),
287             ToscaTagNamesEnum.METADATA);
288         Map<String, Object> mainMetadata = mainMetadataEither.left().value();
289         nodeTypeMetadata.setModel((String) mainMetadata.get("model"));
290         SubCategoryDefinition subCategory = new SubCategoryDefinition();
291         subCategory.setName("Network Elements");
292         CategoryDefinition category = new CategoryDefinition();
293         category.setName("Generic");
294         category.setNormalizedName("generic");
295         category.setIcons(List.of(DEFAULT_ICON));
296         category.setNormalizedName("generic");
297         category.addSubCategory(subCategory);
298         List<CategoryDefinition> categories = new ArrayList<>();
299         categories.add(category);
300         nodeTypeMetadata.setCategories(categories);
301         String[] nodeTemplateName = nodeTemplateType.split("\\.");
302         String name =  nodeTemplateName[nodeTemplateName.length - 1];
303         nodeTypeMetadata.setName(name);
304         List<String> tags = new ArrayList<>();
305         tags.add(name);
306         nodeTypeMetadata.setTags(tags);
307         nodeTypeMetadata.setIcon("defaulticon");
308         nodeTypeMetadata.setVendorName((String) mainMetadata.get("name"));
309         nodeTypeMetadata.setVendorRelease("1");
310         nodeTypeMetadata.setNormative(false);
311     }
312
313 }