056d07aed01948f5471e0f6de268ea8412acc987
[sdc.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation
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  *  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.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 package org.openecomp.core.converter.impl.pnfd.parser;
21
22 import com.google.common.collect.ImmutableMap;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Optional;
28 import java.util.Set;
29 import org.apache.commons.collections.MapUtils;
30 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
31 import org.openecomp.core.converter.ServiceTemplateReaderService;
32 import org.openecomp.core.converter.impl.pnfd.PnfdQueryExecutor;
33 import org.openecomp.core.converter.pnfd.model.ConversionDefinition;
34 import org.openecomp.core.converter.pnfd.model.ConversionQuery;
35 import org.openecomp.core.converter.pnfd.model.PnfTransformationToken;
36 import org.openecomp.core.converter.pnfd.model.Transformation;
37 import org.openecomp.core.converter.pnfd.parser.PnfdBlockParser;
38
39 public abstract class AbstractPnfdBlockParser implements PnfdBlockParser {
40
41     protected final Transformation transformation;
42     protected ServiceTemplateReaderService templateFrom;
43     protected ServiceTemplate templateTo;
44     protected Object attributeValueToBeConverted = "";
45
46     public AbstractPnfdBlockParser(final Transformation transformation) {
47         this.transformation = transformation;
48     }
49
50     /**
51      * Parses a PNFD block based on the {@link Transformation} provided during the {@link PnfdBlockParser}
52      * instantiation.
53      *
54      * @param templateFrom the original PNFD template
55      * @param templateTo the resulting PNFD template
56      */
57     public void parse(final ServiceTemplateReaderService templateFrom, final ServiceTemplate templateTo) {
58         this.templateFrom = templateFrom;
59         this.templateTo = templateTo;
60         final Set<Map<String, Object>> blockToParseSet = findBlocksToParse();
61         if (!blockToParseSet.isEmpty()) {
62             blockToParseSet.forEach(this::parse);
63         }
64     }
65
66     /**
67      * Applies all specified conversions in {@link Transformation#getConversionDefinitionList()} for the given
68      * blockYamlObject.
69      *
70      * @param blockYamlObject the block content as a YAML object
71      */
72     protected void parse(final Map<String, Object> blockYamlObject) {
73         if (MapUtils.isEmpty(blockYamlObject)) {
74             return;
75         }
76         final List<ConversionDefinition> conversionDefinitionList = transformation.getConversionDefinitionList();
77         final Map<String, Object> parsedBlockYamlObject = new HashMap<>();
78         final String blockName = blockYamlObject.keySet().iterator().next();
79         conversionDefinitionList.stream()
80             .filter(conversionDefinition -> conversionDefinition.getConversionQuery().isValidAttributeQuery())
81             .forEach(conversionDefinition -> {
82                 final Map<String, Object> query =
83                     (Map<String, Object>) conversionDefinition.getConversionQuery().getQuery();
84                 final Map<String, Object> blockAttributeMap = (Map<String, Object>) blockYamlObject.get(blockName);
85                 final Optional<Map<String, Object>> parsedBlockAttributeMap = buildParsedBlock(query, blockAttributeMap
86                     , conversionDefinition);
87                 parsedBlockAttributeMap.ifPresent(convertedNodeTemplateAttributeMap1 ->
88                     mergeYamlObjects(parsedBlockYamlObject, convertedNodeTemplateAttributeMap1)
89                 );
90             });
91
92         write(blockName, parsedBlockYamlObject);
93     }
94
95     /**
96      * Writes the block in the resulting {@link ServiceTemplate} {@link #templateTo}.
97      *
98      * @param blockName the name of the block
99      * @param parsedBlockYamlObject the block content as a YAML object
100      */
101     protected abstract void write(final String blockName, final Map<String, Object> parsedBlockYamlObject);
102
103     /**
104      * Uses the provided attribute query to find a attribute in the original YAML object and apply the provided
105      * conversion.
106      *
107      * @param attributeQuery the attribute query
108      * @param fromNodeTemplateAttributeMap the original YAML object
109      * @param conversionDefinition the conversion
110      * @return the rebuilt original YAML object with the converted attribute
111      */
112     protected abstract Optional<Map<String, Object>> buildParsedBlock(final Map<String, Object> attributeQuery,
113                                                                       final Map<String, Object> fromNodeTemplateAttributeMap,
114                                                                       final ConversionDefinition conversionDefinition);
115
116     /**
117      * Merges two YAML objects.
118      *
119      * @param originalMap original YAML object
120      * @param toBeMergedMap YAML object to be merged
121      * @return the new YAML object representing the merge result.
122      */
123     protected Map<String, Object> mergeYamlObjects(final Map<String, Object> originalMap,
124         final Map<String, Object> toBeMergedMap) {
125         toBeMergedMap.forEach(
126             (key, value) -> originalMap.merge(key, value,
127                 (toBeMergedValue, originalValue) -> {
128                     if (originalValue instanceof Map) {
129                         return mergeYamlObjects((Map) originalValue, (Map) toBeMergedValue);
130                     }
131                     return originalValue;
132                 })
133         );
134
135         return originalMap;
136     }
137
138     /**
139      * Executes the provided {@link #transformation getConversionQuery} YAML query to find the blocks to be parsed in
140      * {@link #templateFrom}.
141      *
142      * @return The YAML blocks found
143      */
144     protected abstract Set<Map<String, Object>> findBlocksToParse();
145
146     /**
147      * Checks if the YAML object is a TOSCA get_input call
148      *
149      * @param yamlObject the YAML object
150      * @return {@code true} if the YAML object is a TOSCA get_input call, {@code false} otherwise
151      */
152     protected boolean isGetInputFunction(final Object yamlObject) {
153         if (yamlObject instanceof Map) {
154             final Map<String, Object> yamlMap = (Map<String, Object>) yamlObject;
155             return yamlMap.containsKey(PnfTransformationToken.GET_INPUT.getName());
156         }
157
158         return false;
159     }
160
161     /**
162      * Extracts the value from an YAML Object.
163      * @param yamlObject
164      * @return The Object value from the yamlObject parameter.
165      */
166     protected String extractObjectValue(final Object yamlObject) {
167         if (yamlObject instanceof Map) {
168             final Map<String, Object> yamlMap = (Map<String, Object>) yamlObject;
169             return (String) yamlMap.values().stream().findFirst().orElse(null);
170         }
171
172         return null;
173     }
174
175     /**
176      * Gets the stored input names called with TOSCA get_input function and its transformation configured in {@link
177      * ConversionDefinition#getToGetInput()}
178      */
179     public Optional<Map<String, String>> getInputAndTransformationNameMap() {
180         return Optional.empty();
181     }
182
183     /**
184      * Finds all the derived node types from the provided node types.
185      *
186      * @param rootNodeTypeMap a map with the root node types to find the derived ones
187      * @param derivedNodeTypeMap a map that will be filled with the derived node types
188      */
189     private void findAllDerivedNodeType(final Map<String, Object> rootNodeTypeMap,
190                                           final Map<String, Object> derivedNodeTypeMap) {
191         templateFrom.getNodeTypes().entrySet().stream()
192             .filter(nodeEntry -> rootNodeTypeMap.containsKey(extractObjectValue(nodeEntry.getValue())))
193             .forEach(nodeEntry -> {
194                 if (!derivedNodeTypeMap.containsKey(nodeEntry.getKey())) {
195                     derivedNodeTypeMap.put(nodeEntry.getKey(), nodeEntry.getValue());
196                     final ImmutableMap<String, Object> newRootNodeTypeMap = ImmutableMap
197                         .of(nodeEntry.getKey(), nodeEntry.getValue());
198                     findAllDerivedNodeType(newRootNodeTypeMap, derivedNodeTypeMap);
199                 }
200             });
201     }
202
203     /**
204      * Fetches all Custom NodeTypes based on the query result.
205      * @return a map with all custom Node Types that matches with the query result.
206      */
207     protected Map<String, Object> fetchCustomNodeType() {
208         final Map<String, Object> nodeTypesMap = templateFrom.getNodeTypes();
209         if (MapUtils.isEmpty(nodeTypesMap)) {
210             return Collections.emptyMap();
211         }
212         final ConversionQuery conversionQuery = transformation.getConversionQuery();
213         final Map<String, Object> customNodeTypesMap = new HashMap<>();
214         nodeTypesMap.entrySet().stream()
215             .filter(nodeEntry -> PnfdQueryExecutor.find(conversionQuery, nodeEntry.getValue()))
216             .forEach(customNode -> {
217                 attributeValueToBeConverted = extractObjectValue(customNode.getValue());
218                 customNodeTypesMap.put(customNode.getKey(), customNode.getValue());
219             });
220         final Map<String, Object> childNodeTypeMap = new HashMap<>();
221         findAllDerivedNodeType(customNodeTypesMap, childNodeTypeMap);
222         customNodeTypesMap.putAll(childNodeTypeMap);
223         return customNodeTypesMap;
224     }
225
226 }