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