Implement PNFD Model driven conversion
[sdc.git] / openecomp-be / lib / openecomp-tosca-converter-lib / openecomp-tosca-converter-api / src / main / java / org / openecomp / core / converter / pnfd / parser / AbstractPnfdBlockParser.java
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.pnfd.parser;
21
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Optional;
26 import java.util.Set;
27 import org.apache.commons.collections.MapUtils;
28 import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
29 import org.openecomp.core.converter.ServiceTemplateReaderService;
30 import org.openecomp.core.converter.pnfd.model.ConversionDefinition;
31 import org.openecomp.core.converter.pnfd.model.PnfTransformationToken;
32 import org.openecomp.core.converter.pnfd.model.Transformation;
33
34 public abstract class AbstractPnfdBlockParser implements PnfdBlockParser {
35
36     protected final Transformation transformation;
37     protected ServiceTemplateReaderService templateFrom;
38     protected ServiceTemplate templateTo;
39
40     public AbstractPnfdBlockParser(final Transformation transformation) {
41         this.transformation = transformation;
42     }
43
44     /**
45      * Parses a PNFD block based on the {@link Transformation} provided during the {@link PnfdBlockParser}
46      * instantiation.
47      *
48      * @param templateFrom the original PNFD template
49      * @param templateTo the resulting PNFD template
50      */
51     public void parse(final ServiceTemplateReaderService templateFrom, final ServiceTemplate templateTo) {
52         this.templateFrom = templateFrom;
53         this.templateTo = templateTo;
54         final Set<Map<String, Object>> blockToParseSet = findBlocksToParse();
55         if (!blockToParseSet.isEmpty()) {
56             blockToParseSet.forEach(this::parse);
57         }
58     }
59
60     /**
61      * Applies all specified conversions in {@link Transformation#getConversionDefinitionList()} for the given
62      * blockYamlObject.
63      *
64      * @param blockYamlObject the block content as a YAML object
65      */
66     protected void parse(final Map<String, Object> blockYamlObject) {
67         if (MapUtils.isEmpty(blockYamlObject)) {
68             return;
69         }
70         final List<ConversionDefinition> conversionDefinitionList = transformation.getConversionDefinitionList();
71         final Map<String, Object> parsedBlockYamlObject = new HashMap<>();
72         final String blockName = blockYamlObject.keySet().iterator().next();
73         conversionDefinitionList.stream()
74             .filter(conversionDefinition -> conversionDefinition.getConversionQuery().isValidAttributeQuery())
75             .forEach(conversionDefinition -> {
76                 final Map<String, Object> query =
77                     (Map<String, Object>) conversionDefinition.getConversionQuery().getQuery();
78                 final Map<String, Object> blockAttributeMap = (Map<String, Object>) blockYamlObject.get(blockName);
79                 final Optional<Map<String, Object>> parsedBlockAttributeMap = buildParsedBlock(query, blockAttributeMap
80                     , conversionDefinition);
81                 parsedBlockAttributeMap.ifPresent(convertedNodeTemplateAttributeMap1 ->
82                     mergeYamlObjects(parsedBlockYamlObject, convertedNodeTemplateAttributeMap1)
83                 );
84             });
85
86         write(blockName, parsedBlockYamlObject);
87     }
88
89     /**
90      * Writes the block in the resulting {@link ServiceTemplate} {@link #templateTo}.
91      *
92      * @param blockName the name of the block
93      * @param parsedBlockYamlObject the block content as a YAML object
94      */
95     protected abstract void write(final String blockName, final Map<String, Object> parsedBlockYamlObject);
96
97     /**
98      * Uses the provided attribute query to find a attribute in the original YAML object and apply the provided
99      * conversion.
100      *
101      * @param attributeQuery the attribute query
102      * @param fromNodeTemplateAttributeMap the original YAML object
103      * @param conversionDefinition the conversion
104      * @return the rebuilt original YAML object with the converted attribute
105      */
106     protected abstract Optional<Map<String, Object>> buildParsedBlock(final Map<String, Object> attributeQuery,
107         final Map<String, Object> fromNodeTemplateAttributeMap,
108         final ConversionDefinition conversionDefinition);
109
110     /**
111      * Merges two YAML objects.
112      *
113      * @param originalMap original YAML object
114      * @param toBeMergedMap YAML object to be merged
115      * @return the new YAML object representing the merge result.
116      */
117     protected Map<String, Object> mergeYamlObjects(final Map<String, Object> originalMap,
118         final Map<String, Object> toBeMergedMap) {
119         toBeMergedMap.forEach(
120             (key, value) -> originalMap.merge(key, value,
121                 (toBeMergedValue, originalValue) -> {
122                     if (originalValue instanceof Map) {
123                         return mergeYamlObjects((Map) originalValue, (Map) toBeMergedValue);
124                     }
125                     return originalValue;
126                 })
127         );
128
129         return originalMap;
130     }
131
132     /**
133      * Executes the provided {@link #transformation getConversionQuery} YAML query to find the blocks to be parsed in
134      * {@link #templateFrom}.
135      *
136      * @return The YAML blocks found
137      */
138     protected abstract Set<Map<String, Object>> findBlocksToParse();
139
140     /**
141      * Checks if the YAML object is a TOSCA get_input call
142      *
143      * @param yamlObject the YAML object
144      * @return {@code true} if the YAML object is a TOSCA get_input call, {@code false} otherwise
145      */
146     protected boolean isGetInputFunction(final Object yamlObject) {
147         if (yamlObject instanceof Map) {
148             final Map<String, Object> yamlMap = (Map<String, Object>) yamlObject;
149             return yamlMap.containsKey(PnfTransformationToken.GET_INPUT.getName());
150         }
151
152         return false;
153     }
154
155     /**
156      * Gets the value (input name) of a YAML object representing a TOSCA get_input call: "get_input: <i>value</i>".
157      *
158      * @param yamlObject the YAML object
159      * @return The get_input function value, that represents the input name
160      */
161     protected String extractGetInputFunctionValue(final Object yamlObject) {
162         if (yamlObject instanceof Map) {
163             final Map<String, Object> yamlMap = (Map<String, Object>) yamlObject;
164             return (String) yamlMap.values().stream().findFirst().orElse(null);
165         }
166
167         return null;
168     }
169
170     /**
171      * Gets the stored input names called with TOSCA get_input function and its transformation configured in {@link
172      * ConversionDefinition#getToGetInput()}
173      */
174     public Optional<Map<String, String>> getInputAndTransformationNameMap() {
175         return Optional.empty();
176     }
177
178 }