2 * Copyright © 2016-2020 European Support Limited
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * 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.
16 package org.openecomp.sdc.be.tosca;
18 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT;
19 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS;
20 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS;
22 import com.fasterxml.jackson.annotation.JsonInclude;
23 import com.fasterxml.jackson.databind.DeserializationFeature;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.google.gson.Gson;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Map.Entry;
31 import java.util.Objects;
33 import java.util.stream.Collectors;
34 import org.apache.commons.collections.MapUtils;
35 import org.apache.commons.collections4.CollectionUtils;
36 import org.apache.commons.lang3.StringUtils;
37 import org.apache.commons.lang3.math.NumberUtils;
38 import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition;
39 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
40 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
41 import org.openecomp.sdc.be.model.Component;
42 import org.openecomp.sdc.be.model.ComponentInstance;
43 import org.openecomp.sdc.be.model.DataTypeDefinition;
44 import org.openecomp.sdc.be.model.InterfaceDefinition;
45 import org.openecomp.sdc.be.model.Product;
46 import org.openecomp.sdc.be.model.PropertyDefinition;
47 import org.openecomp.sdc.be.tosca.PropertyConvertor.PropertyType;
48 import org.openecomp.sdc.be.tosca.model.ToscaArtifactDefinition;
49 import org.openecomp.sdc.be.tosca.model.ToscaInput;
50 import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition;
51 import org.openecomp.sdc.be.tosca.model.ToscaInterfaceNodeType;
52 import org.openecomp.sdc.be.tosca.model.ToscaInterfaceOperationImplementation;
53 import org.openecomp.sdc.be.tosca.model.ToscaLifecycleOperationDefinition;
54 import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
55 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
56 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
57 import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum;
58 import org.openecomp.sdc.tosca.datatypes.ToscaFunctions;
59 import org.springframework.beans.factory.annotation.Autowired;
60 import org.springframework.stereotype.Service;
63 public class InterfacesOperationsConverter {
65 public static final String SELF = "SELF";
66 private static final String DERIVED_FROM_STANDARD_INTERFACE = "tosca.interfaces.node.lifecycle.Standard";
67 private static final String DERIVED_FROM_BASE_DEFAULT = "org.openecomp.interfaces.node.lifecycle.";
68 private static final String DEFAULT_HAS_UNDERSCORE = "_default";
69 private static final String DOT = ".";
70 private static final String DEFAULTP = "defaultp";
71 private static final String LOCAL_INTERFACE_TYPE = "Local";
72 private final PropertyConvertor propertyConvertor;
75 public InterfacesOperationsConverter(final PropertyConvertor propertyConvertor) {
76 this.propertyConvertor = propertyConvertor;
80 * Creates the interface_types element.
82 * @param component to work on
83 * @return the added element
85 public static Map<String, Object> addInterfaceTypeElement(Component component, List<String> allInterfaceTypes) {
86 if (component instanceof Product) {
89 final Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
90 if (MapUtils.isEmpty(interfaces)) {
93 Map<String, Object> toscaInterfaceTypes = new HashMap<>();
94 for (InterfaceDefinition interfaceDefinition : interfaces.values()) {
95 boolean isInterfaceTypeExistInGlobalType = allInterfaceTypes.stream()
96 .anyMatch(type -> type.equalsIgnoreCase(interfaceDefinition.getType()));
97 if (!isInterfaceTypeExistInGlobalType) {
98 ToscaInterfaceNodeType toscaInterfaceType = new ToscaInterfaceNodeType();
99 toscaInterfaceType.setDerived_from(DERIVED_FROM_STANDARD_INTERFACE);
100 final Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations();
101 Map<String, Object> toscaOperations = new HashMap<>();
102 for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
103 toscaOperations.put(operationEntry.getValue().getName(), null);
105 toscaInterfaceType.setOperations(toscaOperations);
106 Map<String, Object> interfacesAsMap = getObjectAsMap(toscaInterfaceType);
107 Map<String, Object> operationsMap = (Map<String, Object>) interfacesAsMap.remove(OPERATIONS.getElementName());
108 interfacesAsMap.putAll(operationsMap);
109 toscaInterfaceTypes.put(getInterfaceType(component, LOCAL_INTERFACE_TYPE), interfacesAsMap);
112 return MapUtils.isNotEmpty(toscaInterfaceTypes) ? toscaInterfaceTypes : null;
115 private static Object getDefaultValue(Map<String, Object> inputValueMap) {
116 Object defaultValue = null;
117 for (Map.Entry<String, Object> operationEntry : inputValueMap.entrySet()) {
118 final Object value = operationEntry.getValue();
119 if (value instanceof Map) {
120 getDefaultValue((Map<String, Object>) value);
122 final String key = operationEntry.getKey();
123 if (key.equals(DEFAULTP)) {
124 defaultValue = inputValueMap.remove(key);
130 //Remove input type and copy default value directly into the proxy node template from the node type
131 private static void handleOperationInputValue(Map<String, Object> operationsMap, String parentKey) {
132 for (Map.Entry<String, Object> operationEntry : operationsMap.entrySet()) {
133 final Object value = operationEntry.getValue();
134 final String key = operationEntry.getKey();
135 if (value instanceof Map) {
136 if (INPUTS.getElementName().equals(parentKey)) {
137 Object defaultValue = getDefaultValue((Map<String, Object>) value);
138 operationsMap.put(key, defaultValue);
140 handleOperationInputValue((Map<String, Object>) value, key);
146 private static String getLastPartOfName(String toscaResourceName) {
147 return toscaResourceName.substring(toscaResourceName.lastIndexOf(DOT) + 1);
150 private static boolean isArtifactPresent(Map.Entry<String, OperationDataDefinition> operationEntry) {
151 final boolean isImplementationPresent = !Objects.isNull(operationEntry.getValue().getImplementation());
152 if (isImplementationPresent) {
153 return !Objects.isNull(operationEntry.getValue().getImplementation().getArtifactName());
158 private static String getInputValue(String inputValue) {
159 String toscaInputValue = inputValue;
160 if (Objects.nonNull(inputValue) && inputValue.contains(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName())) {
161 Gson gson = new Gson();
162 Map<String, List<String>> consumptionValue = gson.fromJson(inputValue, Map.class);
163 List<String> mappedOutputValue = consumptionValue.get(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName());
164 //Extract the interface name from the interface type
165 String interfaceType = mappedOutputValue.get(1);
166 String interfaceName = interfaceType.substring(interfaceType.lastIndexOf('.') + 1);
167 mappedOutputValue.remove(1);
168 mappedOutputValue.add(1, interfaceName);
169 toscaInputValue = gson.toJson(consumptionValue);
171 return toscaInputValue;
174 private static String getInterfaceType(Component component, String interfaceType) {
175 if (LOCAL_INTERFACE_TYPE.equals(interfaceType)) {
176 return DERIVED_FROM_BASE_DEFAULT + component.getComponentMetadataDefinition().getMetadataDataDefinition().getSystemName();
178 return interfaceType;
181 private static Map<String, Object> getObjectAsMap(Object obj) {
182 ObjectMapper objectMapper = new ObjectMapper();
183 if (obj instanceof ToscaInterfaceDefinition) {
184 //Prevent empty field serialization in interface definition
185 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
187 Map<String, Object> objectAsMap = obj instanceof Map ? (Map<String, Object>) obj : objectMapper.convertValue(obj, Map.class);
188 final String defaultEntry = DEFAULT.getElementName();
189 if (objectAsMap.containsKey(defaultEntry)) {
190 objectAsMap.put(DEFAULT_HAS_UNDERSCORE, objectAsMap.remove(defaultEntry));
196 * Adds the 'interfaces' element to the node type provided.
198 * @param component to work on
199 * @param nodeType to which the interfaces element will be added
201 public void addInterfaceDefinitionElement(Component component, ToscaNodeType nodeType, Map<String, DataTypeDefinition> dataTypes,
202 boolean isAssociatedComponent) {
203 if (component instanceof Product) {
206 final Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
207 if (MapUtils.isEmpty(interfaces)) {
210 Map<String, Object> toscaInterfaceDefinitions = getInterfacesMap(component, dataTypes, isAssociatedComponent);
211 if (MapUtils.isNotEmpty(toscaInterfaceDefinitions)) {
212 nodeType.setInterfaces(toscaInterfaceDefinitions);
216 private Map<String, Object> getInterfacesMap(Component component, Map<String, DataTypeDefinition> dataTypes, boolean isAssociatedComponent) {
217 return getInterfacesMap(component, null, component.getInterfaces(), dataTypes, isAssociatedComponent, false);
220 public Map<String, Object> getInterfacesMap(final Component component, final ComponentInstance componentInstance,
221 final Map<String, InterfaceDefinition> interfaces, final Map<String, DataTypeDefinition> dataTypes,
222 final boolean isAssociatedComponent, final boolean isServiceProxyInterface) {
223 if (MapUtils.isEmpty(interfaces)) {
226 final Map<String, Object> toscaInterfaceDefinitions = new HashMap<>();
227 for (InterfaceDefinition interfaceDefinition : interfaces.values()) {
228 handleInterfaceOperations(component, componentInstance, dataTypes, isAssociatedComponent, isServiceProxyInterface,
229 toscaInterfaceDefinitions, interfaceDefinition);
231 return toscaInterfaceDefinitions;
234 public Map<String, Object> getInterfacesMapFromComponentInstance(final Component component, final ComponentInstance componentInstance,
235 final Map<String, DataTypeDefinition> dataTypes,
236 final boolean isAssociatedComponent, final boolean isServiceProxyInterface) {
237 final Map<String, Object> toscaInterfaceDefinitions = new HashMap<>();
238 final ObjectMapper objectMapper = new ObjectMapper();
239 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
240 for (final Map.Entry<String, Object> interfaceEntry : componentInstance.getInterfaces().entrySet()) {
241 final InterfaceDefinition interfaceDefinition = objectMapper.convertValue(interfaceEntry.getValue(), InterfaceDefinition.class);
242 handleInterfaceOperations(component, componentInstance, dataTypes, isAssociatedComponent, isServiceProxyInterface,
243 toscaInterfaceDefinitions, interfaceDefinition);
245 return toscaInterfaceDefinitions;
248 private void handleInterfaceOperations(final Component component, final ComponentInstance componentInstance,
249 final Map<String, DataTypeDefinition> dataTypes, final boolean isAssociatedComponent,
250 final boolean isServiceProxyInterface, final Map<String, Object> toscaInterfaceDefinitions,
251 final InterfaceDefinition interfaceDefinition) {
252 final String interfaceType;
253 if (componentInstance != null && LOCAL_INTERFACE_TYPE.equals(interfaceDefinition.getType())) {
254 interfaceType = DERIVED_FROM_BASE_DEFAULT + componentInstance.getSourceModelName();
256 interfaceType = getInterfaceType(component, interfaceDefinition.getType());
258 final ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition();
259 if (componentInstance == null) {
260 toscaInterfaceDefinition.setType(interfaceType);
262 final Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations();
263 final Map<String, Object> toscaOperationMap = new HashMap<>();
264 for (final Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
265 final ToscaLifecycleOperationDefinition toscaLifecycleOperationDefinition = new ToscaLifecycleOperationDefinition();
266 handleInterfaceOperationImplementation(component, componentInstance, isAssociatedComponent, operationEntry,
267 toscaLifecycleOperationDefinition);
268 toscaLifecycleOperationDefinition.setDescription(operationEntry.getValue().getDescription());
269 fillToscaOperationInputs(operationEntry.getValue(), dataTypes, toscaLifecycleOperationDefinition, isServiceProxyInterface);
270 toscaOperationMap.put(operationEntry.getValue().getName(), toscaLifecycleOperationDefinition);
272 toscaInterfaceDefinition.setOperations(toscaOperationMap);
273 final Map<String, Object> interfaceInputMap = createInterfaceInputMap(interfaceDefinition, dataTypes);
274 if (!interfaceInputMap.isEmpty()) {
275 toscaInterfaceDefinition.setInputs(interfaceInputMap);
277 final Map<String, Object> interfaceDefinitionAsMap = getObjectAsMap(toscaInterfaceDefinition);
278 if (interfaceDefinitionAsMap.containsKey(INPUTS.getElementName())) {
279 handleDefaults((Map<String, Object>) interfaceDefinitionAsMap.get(INPUTS.getElementName()));
281 final Map<String, Object> operationsMap = (Map<String, Object>) interfaceDefinitionAsMap.remove(OPERATIONS.getElementName());
282 handleOperationInputValue(operationsMap, interfaceType);
283 interfaceDefinitionAsMap.putAll(operationsMap);
284 toscaInterfaceDefinitions.put(getLastPartOfName(interfaceType), interfaceDefinitionAsMap);
287 private void handleInterfaceOperationImplementation(final Component component, final ComponentInstance componentInstance,
288 final boolean isAssociatedComponent,
289 final Entry<String, OperationDataDefinition> operationEntry,
290 final ToscaLifecycleOperationDefinition toscaOperation) {
291 final String operationArtifactPath;
292 final ToscaInterfaceOperationImplementation toscaInterfaceOperationImplementation = new ToscaInterfaceOperationImplementation();
293 toscaInterfaceOperationImplementation.setPrimary(new ToscaArtifactDefinition());
294 final ToscaArtifactDefinition toscaArtifactDefinition = toscaInterfaceOperationImplementation.getPrimary();
295 if (isArtifactPresent(operationEntry) && StringUtils.isNotEmpty(operationEntry.getValue().getImplementation().getArtifactName())) {
296 operationArtifactPath = OperationArtifactUtil
297 .createOperationArtifactPath(component, componentInstance, operationEntry.getValue(), isAssociatedComponent);
298 toscaArtifactDefinition.setFile(operationArtifactPath);
299 toscaArtifactDefinition.setArtifact_version(!operationEntry.getValue().getImplementation().getArtifactVersion()
300 .equals(NumberUtils.INTEGER_ZERO.toString()) ? operationEntry.getValue().getImplementation().getArtifactVersion() : null);
301 toscaArtifactDefinition.setType(operationEntry.getValue().getImplementation().getArtifactType());
302 handleInterfaceOperationImplementationProperties(operationEntry, toscaArtifactDefinition);
303 toscaOperation.setImplementation(
304 toscaArtifactDefinition.getType() != null ? toscaInterfaceOperationImplementation : operationArtifactPath);
306 toscaArtifactDefinition.setFile(operationEntry.getValue().getImplementation().getArtifactName());
307 toscaOperation.setImplementation(toscaInterfaceOperationImplementation);
311 private void handleInterfaceOperationImplementationProperties(final Entry<String, OperationDataDefinition> operationEntry,
312 final ToscaArtifactDefinition toscaArtifactDefinition) {
313 final var properties = operationEntry.getValue().getImplementation().getProperties();
314 if (CollectionUtils.isNotEmpty(properties)) {
315 final Map<String, String> propertiesMap = new HashMap<>();
316 properties.stream().filter(propertyDataDefinition -> StringUtils.isNotEmpty(propertyDataDefinition.getValue()))
317 .forEach(propertyDataDefinition -> propertiesMap.put(propertyDataDefinition.getName(), propertyDataDefinition.getValue()));
318 toscaArtifactDefinition.setProperties(propertiesMap);
322 public void removeInterfacesWithoutOperations(final Map<String, Object> interfaceMap) {
323 if (MapUtils.isEmpty(interfaceMap)) {
326 final Set<String> emptyInterfaces = interfaceMap.entrySet().stream().filter(entry -> {
327 final Object value = entry.getValue();
328 if (value instanceof ToscaInterfaceDefinition) {
329 final ToscaInterfaceDefinition interfaceDefinition = (ToscaInterfaceDefinition) value;
330 return MapUtils.isEmpty(interfaceDefinition.getOperations());
331 } else if (value instanceof Map) {
332 final Map<String, Object> interfaceDefMap = (Map<String, Object>) value;
333 return MapUtils.isEmpty(interfaceDefMap);
336 }).map(Entry::getKey).collect(Collectors.toSet());
337 emptyInterfaces.forEach(interfaceMap::remove);
340 private Map<String, Object> createInterfaceInputMap(final InterfaceDefinition interfaceDefinition,
341 final Map<String, DataTypeDefinition> allDataTypeMap) {
342 final Map<String, InputDataDefinition> inputMap = interfaceDefinition.getInputs();
343 if (MapUtils.isEmpty(inputMap)) {
344 return Collections.emptyMap();
346 final Map<String, Object> toscaInterfaceInputMap = new HashMap<>();
347 for (final Entry<String, InputDataDefinition> inputEntry : inputMap.entrySet()) {
348 final InputDataDefinition inputDataDefinition = inputEntry.getValue();
349 final ToscaProperty toscaProperty = propertyConvertor
350 .convertProperty(allDataTypeMap, new PropertyDefinition(inputDataDefinition), PropertyType.INPUT);
351 toscaInterfaceInputMap.put(inputEntry.getKey(), new ToscaInput(toscaProperty));
353 return toscaInterfaceInputMap;
357 * workaround for : currently "defaultp" is not being converted to "default" by the relevant code in
358 * ToscaExportHandler so, any string Map key named "defaultp" will have its named changed to "default"
359 * @param operationsMap the map to update
361 private void handleDefaults(Map<String, Object> operationsMap) {
362 for (Map.Entry<String, Object> operationEntry : operationsMap.entrySet()) {
363 final Object value = operationEntry.getValue();
364 if (value instanceof Map) {
365 handleDefaults((Map<String, Object>) value);
367 final String key = operationEntry.getKey();
368 if (key.equals(DEFAULTP)) {
369 Object removed = operationsMap.remove(key);
370 operationsMap.put(ToscaTagNamesEnum.DEFAULT.getElementName(), removed);
375 private void fillToscaOperationInputs(OperationDataDefinition operation, Map<String, DataTypeDefinition> dataTypes,
376 ToscaLifecycleOperationDefinition toscaOperation, boolean isServiceProxyInterface) {
377 if (Objects.isNull(operation.getInputs()) || operation.getInputs().isEmpty()) {
378 toscaOperation.setInputs(null);
381 Map<String, ToscaProperty> toscaInputs = new HashMap<>();
382 for (OperationInputDefinition input : operation.getInputs().getListToscaDataDefinition()) {
383 ToscaProperty toscaInput = new ToscaProperty();
384 toscaInput.setDescription(input.getDescription());
385 toscaInput.setType(input.getType());
386 toscaInput.setRequired(input.isRequired());
387 if (isServiceProxyInterface) {
388 String inputValue = Objects.nonNull(input.getValue()) ? getInputValue(input.getValue()) : getInputValue(input.getToscaDefaultValue());
389 toscaInput.setDefaultp(propertyConvertor.convertToToscaObject(input, inputValue, dataTypes, false));
391 toscaInput.setDefaultp(propertyConvertor.convertToToscaObject(input, getInputValue(input.getToscaDefaultValue()), dataTypes, false));
393 toscaInputs.put(input.getName(), toscaInput);
395 toscaOperation.setInputs(toscaInputs);