54cd29868b814aef1e77e680122f671aa221d670
[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.NullNodeTypeMetadata;
48 import org.openecomp.sdc.be.model.User;
49 import org.openecomp.sdc.be.model.category.CategoryDefinition;
50 import org.openecomp.sdc.be.model.category.SubCategoryDefinition;
51 import org.openecomp.sdc.be.utils.TypeUtils;
52 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
53 import org.openecomp.sdc.common.log.wrappers.Logger;
54 import org.yaml.snakeyaml.Yaml;
55
56 /**
57  * Provides access to the contents of a Service CSAR
58  */
59 public class ServiceCsarInfo extends CsarInfo {
60
61     private static final Logger log = Logger.getLogger(ServiceCsarInfo.class);
62     private final Map<String, Map<String, Object>> mainTemplateImports;
63     private List<NodeTypeDefinition> nodeTypeDefinitions;
64
65     public ServiceCsarInfo(final User modifier, final String csarUUID, final Map<String, byte[]> csar, final String vfResourceName,
66                            final String mainTemplateName, final String mainTemplateContent, final boolean isUpdate) {
67         super(modifier, csarUUID, csar, vfResourceName, mainTemplateName, mainTemplateContent, isUpdate);
68
69         final Path mainTemplateDir = Paths.get(getMainTemplateName().substring(0, getMainTemplateName().lastIndexOf('/') + 1));
70         final Collection<Path> filesHandled = new HashSet<>();
71         filesHandled.add(Paths.get(mainTemplateName));
72         this.mainTemplateImports = getTemplateImports(csar, new Yaml().load(mainTemplateContent), mainTemplateDir, filesHandled);
73     }
74
75     private Map<String, Map<String, Object>> getTemplateImports(final Map<String, byte[]> csar, Map<String, Object> mappedToscaMainTemplate,
76                                                                 final Path fileParentDir, final Collection<Path> filesHandled) {
77         final Map<String, Map<String, Object>> templateImports = new HashMap<>();
78
79         final List<Path> importFilePaths = getTemplateImportFilePaths(mappedToscaMainTemplate, fileParentDir);
80
81         importFilePaths.stream().filter(path -> !filesHandled.contains(path)).forEach(
82             importFilePath -> {
83                 byte[] importFile = csar.get(importFilePath.toString());
84                 if (importFile != null) {
85                     filesHandled.add(importFilePath);
86                     Map<String, Object> mappedImportFile = new Yaml().load(new String(csar.get(importFilePath.toString())));
87                     templateImports.put(importFilePath.toString(), mappedImportFile);
88                     templateImports.putAll(getTemplateImports(csar, mappedImportFile, importFilePath.getParent(), filesHandled));
89                 } else {
90                     log.info("Import {} cannot be found in CSAR", importFilePath.toString());
91                 }
92             });
93
94         return templateImports;
95     }
96
97     @SuppressWarnings({"unchecked", "rawtypes"})
98     private List<Path> getTemplateImportFilePaths(final Map<String, Object> mappedToscaTemplate, final Path fileParentDir) {
99         final Either<Object, ResultStatusEnum> importsEither =
100             findToscaElement(mappedToscaTemplate, ToscaTagNamesEnum.IMPORTS, ToscaElementTypeEnum.ALL);
101
102         if (importsEither.isLeft()) {
103             final List importsList = (List) importsEither.left().value();
104             if (CollectionUtils.isNotEmpty(importsList)) {
105                 if (importsList.get(0) instanceof String) {
106                     List<Path> importPaths = new ArrayList<>();
107                     importsList.stream()
108                         .forEach(importPath -> importPaths.add(fileParentDir == null ? Paths.get((String) importPath)
109                             : fileParentDir.resolve(Paths.get((String) importPath)).normalize()));
110                     return importPaths;
111                 } else if (importsList.get(0) instanceof Map) {
112                     return getTemplateImportFilePathsMultiLineGrammar(importsList, fileParentDir);
113                 }
114             }
115
116         }
117         return Collections.emptyList();
118     }
119
120     @SuppressWarnings("unchecked")
121     private List<Path> getTemplateImportFilePathsMultiLineGrammar(final List<Map<String, Object>> importsList, final Path fileParentDir) {
122         final List<Path> importFiles = new ArrayList<>();
123
124         for (Map<String, Object> importFileMultiLineGrammar : importsList) {
125             if (MapUtils.isNotEmpty(importFileMultiLineGrammar)) {
126                 if (importFileMultiLineGrammar.values().iterator().next() instanceof String) {
127                     Path relativePath = Paths.get((String) importFileMultiLineGrammar.get("file"));
128                     Path absolutePath = fileParentDir == null ? relativePath : fileParentDir.resolve(relativePath).normalize();
129                     importFiles.add(absolutePath);
130                 } else if (importFileMultiLineGrammar.values().iterator().next() instanceof Map) {
131                     importFileMultiLineGrammar.values().forEach(value -> {
132                         Path relativePath = Paths.get((String) ((Map<String, Object>) value).get("file"));
133                         Path absolutePath = fileParentDir == null ? relativePath : fileParentDir.resolve(relativePath).normalize();
134                         importFiles.add(absolutePath);
135                     });
136                 }
137             }
138         }
139         return importFiles;
140     }
141
142     @Override
143     public Map<String, NodeTypeInfo> extractTypesInfo() {
144         return Collections.emptyMap();
145     }
146
147     @Override
148     public Map<String, Object> getDataTypes() {
149         return getTypes(ToscaTagNamesEnum.DATA_TYPES);
150     }
151
152     @Override
153     public Map<String, Object> getGroupTypes() {
154         return getTypes(ToscaTagNamesEnum.GROUP_TYPES);
155     }
156
157     @Override
158     public Map<String, Object> getCapabilityTypes() {
159         return getTypes(ToscaTagNamesEnum.CAPABILITY_TYPES);
160     }
161
162     private Map<String, Object> getTypes(ToscaTagNamesEnum toscaTag) {
163         final Map<String, Object> types = new HashMap<>();
164         mainTemplateImports.entrySet().stream().forEach(entry -> types.putAll(getTypesFromTemplate(entry.getValue(), toscaTag)));
165         types.putAll(getTypesFromTemplate(getMappedToscaMainTemplate(), toscaTag));
166         return types;
167     }
168
169     public Map<String, Object> getArtifactTypes() {
170         final Map<String, Object> artifactsTypes = new HashMap<>();
171         mainTemplateImports.entrySet().stream()
172             .forEach(entry -> artifactsTypes.putAll(getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.ARTIFACT_TYPES)));
173         artifactsTypes.putAll(getTypesFromTemplate(getMappedToscaMainTemplate(), TypeUtils.ToscaTagNamesEnum.ARTIFACT_TYPES));
174         return artifactsTypes;
175     }
176
177     public List<NodeTypeDefinition> getNodeTypesUsed() {
178         if (nodeTypeDefinitions == null) {
179             nodeTypeDefinitions = new ArrayList<>();
180             final Set<String> nodeTypesUsed = getNodeTypesUsedInToscaTemplate(getMappedToscaMainTemplate());
181             nodeTypeDefinitions.addAll(getNodeTypeDefinitions(nodeTypesUsed));
182         }
183         nodeTypeDefinitions = sortNodeTypesByDependencyOrder(nodeTypeDefinitions);
184         return nodeTypeDefinitions;
185     }
186
187     private List<NodeTypeDefinition> sortNodeTypesByDependencyOrder(final List<NodeTypeDefinition> nodeTypes) {
188         final List<NodeTypeDefinition> sortedNodeTypeDefinitions = new ArrayList<>();
189         final Map<String, NodeTypeDefinition> nodeTypeDefinitionsMap = new HashMap<>();
190
191         nodeTypes.forEach(nodeType -> {
192             int highestDependencyIndex = -1;
193             for (final String dependencyName : getDependencyTypes(nodeType, nodeTypes)) {
194                 final NodeTypeDefinition dependency = nodeTypeDefinitionsMap.get(dependencyName);
195                 final int indexOfDependency = sortedNodeTypeDefinitions.lastIndexOf(dependency);
196                 highestDependencyIndex = indexOfDependency > highestDependencyIndex ? indexOfDependency : highestDependencyIndex;
197             }
198             sortedNodeTypeDefinitions.add(highestDependencyIndex + 1, nodeType);
199             nodeTypeDefinitionsMap.put(nodeType.getMappedNodeType().getKey(), nodeType);
200         });
201         return sortedNodeTypeDefinitions;
202     }
203
204     private Collection<String> getDependencyTypes(final NodeTypeDefinition nodeType, final List<NodeTypeDefinition> nodeTypes) {
205         final Set<String> dependencies = new HashSet<>();
206         Either<Object, ResultStatusEnum> derivedFromTypeEither = findToscaElement((Map<String, Object>) nodeType.getMappedNodeType().getValue(),
207             TypeUtils.ToscaTagNamesEnum.DERIVED_FROM, ToscaElementTypeEnum.STRING);
208         if (derivedFromTypeEither.isLeft() && derivedFromTypeEither.left().value() != null) {
209             final String derivedFrom = (String) derivedFromTypeEither.left().value();
210             dependencies.add(derivedFrom);
211             nodeTypes.stream().filter(derivedFromCandidate -> derivedFrom.contentEquals(derivedFromCandidate.getMappedNodeType().getKey()))
212                 .forEach(derivedFromNodeType -> dependencies.addAll(getDependencyTypes(derivedFromNodeType, nodeTypes)));
213         }
214         return dependencies;
215     }
216
217     private Set<NodeTypeDefinition> getNodeTypeDefinitions(final Set<String> nodeTypesToGet) {
218         final Set<NodeTypeDefinition> nodeTypesToReturn = new HashSet<>();
219         final Set<NodeTypeDefinition> foundNodeTypes = getTypes(nodeTypesToGet);
220         nodeTypesToReturn.addAll(foundNodeTypes);
221         final Set<String> recursiveNodeTypesToGet = new HashSet<>();
222         foundNodeTypes.stream().forEach(nodeTypeDef -> {
223             Either<Object, ResultStatusEnum> derivedFromTypeEither =
224                 findToscaElement((Map<String, Object>) nodeTypeDef.getMappedNodeType().getValue(), TypeUtils.ToscaTagNamesEnum.DERIVED_FROM,
225                     ToscaElementTypeEnum.STRING);
226             if (derivedFromTypeEither.isLeft()) {
227                 recursiveNodeTypesToGet.add((String) derivedFromTypeEither.left().value());
228             }
229         });
230         recursiveNodeTypesToGet.removeAll(nodeTypesToGet);
231         if (CollectionUtils.isNotEmpty(recursiveNodeTypesToGet)) {
232             nodeTypesToReturn.addAll(getNodeTypeDefinitions(recursiveNodeTypesToGet));
233         }
234         return nodeTypesToReturn;
235     }
236
237
238     private Set<NodeTypeDefinition> getTypes(final Set<String> nodeTypes) {
239         Set<NodeTypeDefinition> nodeTypeDefinitionsLocal = new HashSet<>();
240         mainTemplateImports.entrySet().forEach(entry -> {
241             final Map<String, Object> types = getTypesFromTemplate(entry.getValue(), TypeUtils.ToscaTagNamesEnum.NODE_TYPES, nodeTypes);
242             if (MapUtils.isNotEmpty(types)) {
243                 types.entrySet().stream().forEach(typesEntry -> {
244                     final NodeTypeMetadata metadata =
245                         getMetaDataFromTemplate(entry.getValue(), typesEntry.getKey());
246                     nodeTypeDefinitionsLocal.add(new NodeTypeDefinition(typesEntry, metadata));
247                 });
248             }
249         });
250         return nodeTypeDefinitionsLocal;
251     }
252
253     @SuppressWarnings("unchecked")
254     private Set<String> getNodeTypesUsedInToscaTemplate(Map<String, Object> mappedToscaTemplate) {
255         final Either<Object, ResultStatusEnum> nodeTemplatesEither = findToscaElement(mappedToscaTemplate,
256             TypeUtils.ToscaTagNamesEnum.NODE_TEMPLATES, ToscaElementTypeEnum.MAP);
257         final Set<String> nodeTypesUsedInNodeTemplates = new HashSet<>();
258         if (nodeTemplatesEither.isLeft()) {
259             final Map<String, Map<String, Object>> nodeTemplates =
260                 (Map<String, Map<String, Object>>) nodeTemplatesEither.left().value();
261             nodeTypesUsedInNodeTemplates.addAll(findNodeTypesUsedInNodeTemplates(nodeTemplates));
262         }
263         return nodeTypesUsedInNodeTemplates;
264     }
265
266     private NodeTypeMetadata getMetaDataFromTemplate(Map<String, Object> mappedResourceTemplate, String nodeTemplateType) {
267         NodeTypeMetadata nodeTypeMetadata = new NodeTypeMetadata();
268         Either<Map<String, Object>, ImportUtils.ResultStatusEnum> metadataEither = ImportUtils.findFirstToscaMapElement(mappedResourceTemplate,
269             TypeUtils.ToscaTagNamesEnum.METADATA);
270         if (metadataEither.isLeft() && metadataEither.left().value().get("type").equals(ResourceTypeEnum.VFC.getValue())) {
271             Map<String, Object> metadata = metadataEither.left().value();
272             createMetadataFromTemplate(nodeTypeMetadata, metadata, nodeTemplateType);
273         } else {
274             nodeTypeMetadata = createDefaultMetadata(nodeTemplateType);
275         }
276         return nodeTypeMetadata;
277     }
278
279     private void createMetadataFromTemplate(NodeTypeMetadata nodeTypeMetadata, Map<String, Object> metadata, String nodeTemplateType) {
280         nodeTypeMetadata.setToscaName(nodeTemplateType);
281         nodeTypeMetadata.setContactId(getModifier().getUserId());
282         nodeTypeMetadata.setDescription((String) metadata.get("description"));
283         List<String> tags = new ArrayList<>();
284         tags.add((String) metadata.get("name"));
285         nodeTypeMetadata.setTags(tags);
286         SubCategoryDefinition subCategory = new SubCategoryDefinition();
287         subCategory.setName((String) metadata.get("subcategory"));
288         CategoryDefinition category = new CategoryDefinition();
289         category.setName((String) metadata.get("category"));
290         category.setNormalizedName(((String) metadata.get("category")).toLowerCase());
291         category.setIcons(List.of(DEFAULT_ICON));
292         category.setNormalizedName(((String) metadata.get("category")).toLowerCase());
293         category.addSubCategory(subCategory);
294         List<CategoryDefinition> categories = new ArrayList<>();
295         categories.add(category);
296         nodeTypeMetadata.setCategories(categories);
297         nodeTypeMetadata.setName((String) metadata.get("name"));
298         nodeTypeMetadata.setIcon("defaulticon");
299         nodeTypeMetadata.setResourceVendorModelNumber((String) metadata.get("resourceVendorModelNumber"));
300         nodeTypeMetadata.setResourceType((String) metadata.get("type"));
301         nodeTypeMetadata.setVendorName((String) metadata.get("resourceVendor"));
302         nodeTypeMetadata.setVendorRelease(String.valueOf(metadata.get("resourceVendorRelease")));
303         nodeTypeMetadata.setModel((String) metadata.get("model"));
304         nodeTypeMetadata.setNormative(false);
305     }
306
307     private NullNodeTypeMetadata createDefaultMetadata(String nodeTemplateType) {
308         NullNodeTypeMetadata nodeTypeMetadata = new NullNodeTypeMetadata();
309         nodeTypeMetadata.setToscaName(nodeTemplateType);
310         return nodeTypeMetadata;
311     }
312 }