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.
17 package org.openecomp.sdc.be.tosca;
19 import com.fasterxml.jackson.annotation.JsonInclude;
20 import com.fasterxml.jackson.databind.ObjectMapper;
21 import com.google.gson.Gson;
22 import org.apache.commons.collections.MapUtils;
23 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
24 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
25 import org.openecomp.sdc.be.model.Component;
26 import org.openecomp.sdc.be.model.ComponentInstance;
27 import org.openecomp.sdc.be.model.DataTypeDefinition;
28 import org.openecomp.sdc.be.model.InterfaceDefinition;
29 import org.openecomp.sdc.be.model.Product;
30 import org.openecomp.sdc.tosca.datatypes.ToscaFunctions;
31 import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition;
32 import org.openecomp.sdc.be.tosca.model.ToscaInterfaceNodeType;
33 import org.openecomp.sdc.be.tosca.model.ToscaLifecycleOperationDefinition;
34 import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
35 import org.openecomp.sdc.be.tosca.model.ToscaProperty;
36 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
37 import org.springframework.beans.factory.annotation.Autowired;
38 import org.springframework.stereotype.Service;
40 import java.util.HashMap;
41 import java.util.List;
43 import java.util.Objects;
46 public class InterfacesOperationsConverter {
49 private static final String DERIVED_FROM_STANDARD_INTERFACE = "tosca.interfaces.node.lifecycle.Standard";
50 private static final String DERIVED_FROM_BASE_DEFAULT = "org.openecomp.interfaces.node.lifecycle.";
51 private static final String OPERATIONS_KEY = "operations";
53 private static final String DEFAULT = "default";
54 private static final String DEFAULT_HAS_UNDERSCORE = "_default";
55 private static final String DOT = ".";
56 private static final String DEFAULTP = "defaultp";
58 public static final String SELF = "SELF";
59 private static final String LOCAL_INTERFACE_TYPE = "Local";
61 private PropertyConvertor propertyConvertor;
64 public InterfacesOperationsConverter(PropertyConvertor propertyConvertor) {
65 this.propertyConvertor = propertyConvertor;
69 * Creates the interface_types element.
71 * @param component to work on
72 * @return the added element
74 public static Map<String, Object> addInterfaceTypeElement(Component component, List<String> allInterfaceTypes) {
75 if (component instanceof Product) {
78 final Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
79 if (MapUtils.isEmpty(interfaces)) {
83 Map<String, Object> toscaInterfaceTypes = new HashMap<>();
84 for (InterfaceDefinition interfaceDefinition : interfaces.values()) {
85 boolean isInterfaceTypeExistInGlobalType =
86 allInterfaceTypes.stream().anyMatch(type -> type.equalsIgnoreCase(interfaceDefinition.getType()));
87 if (!isInterfaceTypeExistInGlobalType) {
88 ToscaInterfaceNodeType toscaInterfaceType = new ToscaInterfaceNodeType();
89 toscaInterfaceType.setDerived_from(DERIVED_FROM_STANDARD_INTERFACE);
91 final Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations();
92 Map<String, Object> toscaOperations = new HashMap<>();
94 for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
95 toscaOperations.put(operationEntry.getValue().getName(), null);
97 toscaInterfaceType.setOperations(toscaOperations);
98 Map<String, Object> interfacesAsMap = getObjectAsMap(toscaInterfaceType);
99 Map<String, Object> operationsMap = (Map<String, Object>) interfacesAsMap.remove(OPERATIONS_KEY);
100 interfacesAsMap.putAll(operationsMap);
102 toscaInterfaceTypes.put(getInterfaceType(component, LOCAL_INTERFACE_TYPE), interfacesAsMap);
105 return MapUtils.isNotEmpty(toscaInterfaceTypes) ? toscaInterfaceTypes : null;
109 * Adds the 'interfaces' element to the node type provided.
111 * @param component to work on
112 * @param nodeType to which the interfaces element will be added
114 public void addInterfaceDefinitionElement(Component component, ToscaNodeType nodeType,
115 Map<String, DataTypeDefinition> dataTypes,
116 boolean isAssociatedComponent) {
117 if (component instanceof Product) {
120 final Map<String, InterfaceDefinition> interfaces = component.getInterfaces();
121 if (MapUtils.isEmpty(interfaces)) {
124 Map<String, Object> toscaInterfaceDefinitions = getInterfacesMap(component, dataTypes,
125 isAssociatedComponent);
126 if (MapUtils.isNotEmpty(toscaInterfaceDefinitions)) {
127 nodeType.setInterfaces(toscaInterfaceDefinitions);
131 private Map<String, Object> getInterfacesMap(Component component,
132 Map<String, DataTypeDefinition> dataTypes,
133 boolean isAssociatedComponent) {
134 return getInterfacesMap(component, null, component.getInterfaces(), dataTypes, isAssociatedComponent, false);
137 public Map<String, Object> getInterfacesMap(Component component,
138 ComponentInstance componentInstance,
139 Map<String, InterfaceDefinition> interfaces,
140 Map<String, DataTypeDefinition> dataTypes,
141 boolean isAssociatedComponent,
142 boolean isServiceProxyInterface) {
143 if(MapUtils.isEmpty(interfaces)) {
147 Map<String, Object> toscaInterfaceDefinitions = new HashMap<>();
148 for (InterfaceDefinition interfaceDefinition : interfaces.values()) {
149 ToscaInterfaceDefinition toscaInterfaceDefinition = new ToscaInterfaceDefinition();
150 String interfaceType;
151 if(componentInstance != null && LOCAL_INTERFACE_TYPE.equals(interfaceDefinition.getType())) {
152 interfaceType = DERIVED_FROM_BASE_DEFAULT + componentInstance.getSourceModelName();
154 interfaceType = getInterfaceType(component, interfaceDefinition.getType());
156 toscaInterfaceDefinition.setType(interfaceType);
157 final Map<String, OperationDataDefinition> operations = interfaceDefinition.getOperations();
158 Map<String, Object> toscaOperations = new HashMap<>();
160 String operationArtifactPath;
161 for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
162 ToscaLifecycleOperationDefinition toscaOperation = new ToscaLifecycleOperationDefinition();
163 if (isArtifactPresent(operationEntry)) {
164 operationArtifactPath = OperationArtifactUtil
165 .createOperationArtifactPath(component, componentInstance, operationEntry.getValue(),
166 isAssociatedComponent);
167 toscaOperation.setImplementation(operationArtifactPath);
169 toscaOperation.setDescription(operationEntry.getValue().getDescription());
170 fillToscaOperationInputs(operationEntry.getValue(), dataTypes, toscaOperation, isServiceProxyInterface);
172 toscaOperations.put(operationEntry.getValue().getName(), toscaOperation);
175 toscaInterfaceDefinition.setOperations(toscaOperations);
176 Map<String, Object> interfaceDefAsMap = getObjectAsMap(toscaInterfaceDefinition);
177 Map<String, Object> operationsMap = (Map<String, Object>) interfaceDefAsMap.remove(OPERATIONS_KEY);
178 if (isServiceProxyInterface) {
179 //Remove input type and copy default value directly into the proxy node template from the node type
180 handleServiceProxyOperationInputValue(operationsMap, interfaceType);
182 handleDefaults(operationsMap);
184 interfaceDefAsMap.putAll(operationsMap);
185 toscaInterfaceDefinitions.put(getLastPartOfName(interfaceType), interfaceDefAsMap);
188 return toscaInterfaceDefinitions;
191 private static void handleServiceProxyOperationInputValue(Map<String, Object> operationsMap, String parentKey) {
192 for (Map.Entry<String, Object> operationEntry : operationsMap.entrySet()) {
193 final Object value = operationEntry.getValue();
194 final String key = operationEntry.getKey();
195 if (value instanceof Map) {
196 if ("inputs".equals(parentKey)) {
197 Object defaultValue = getDefaultValue((Map<String, Object>) value);
198 operationsMap.put(key, defaultValue);
200 handleServiceProxyOperationInputValue((Map<String, Object>) value, key);
206 private static Object getDefaultValue(Map<String, Object> inputValueMap) {
207 Object defaultValue = null;
208 for (Map.Entry<String, Object> operationEntry : inputValueMap.entrySet()) {
209 final Object value = operationEntry.getValue();
210 if (value instanceof Map) {
211 getDefaultValue((Map<String, Object>) value);
213 final String key = operationEntry.getKey();
214 if (key.equals(DEFAULTP)) {
215 defaultValue = inputValueMap.remove(key);
222 * workaround for : currently "defaultp" is not being converted to "default" by the relevant code in
223 * ToscaExportHandler so, any string Map key named "defaultp" will have its named changed to "default"
224 * @param operationsMap the map to update
226 private static void handleDefaults(Map<String, Object> operationsMap) {
227 for (Map.Entry<String, Object> operationEntry : operationsMap.entrySet()) {
228 final Object value = operationEntry.getValue();
229 if (value instanceof Map) {
230 handleDefaults((Map<String, Object>) value);
232 final String key = operationEntry.getKey();
233 if (key.equals(DEFAULTP)) {
234 Object removed = operationsMap.remove(key);
235 operationsMap.put(DEFAULT, removed);
240 private static String getLastPartOfName(String toscaResourceName) {
241 return toscaResourceName.substring(toscaResourceName.lastIndexOf(DOT) + 1);
244 private static boolean isArtifactPresent(Map.Entry<String, OperationDataDefinition> operationEntry) {
245 final boolean isImplementationPresent = !Objects.isNull(operationEntry.getValue().getImplementation());
246 if (isImplementationPresent) {
247 return !Objects.isNull(operationEntry.getValue().getImplementation().getArtifactName());
252 private void fillToscaOperationInputs(OperationDataDefinition operation,
253 Map<String, DataTypeDefinition> dataTypes,
254 ToscaLifecycleOperationDefinition toscaOperation,
255 boolean isServiceProxyInterface) {
256 if (Objects.isNull(operation.getInputs()) || operation.getInputs().isEmpty()) {
257 toscaOperation.setInputs(null);
260 Map<String, ToscaProperty> toscaInputs = new HashMap<>();
262 for (OperationInputDefinition input : operation.getInputs().getListToscaDataDefinition()) {
263 ToscaProperty toscaInput = new ToscaProperty();
264 toscaInput.setDescription(input.getDescription());
265 toscaInput.setType(input.getType());
266 toscaInput.setRequired(input.isRequired());
267 if (isServiceProxyInterface) {
268 String inputValue = Objects.nonNull(input.getValue()) ? getInputValue(input.getValue()) :
269 getInputValue(input.getToscaDefaultValue());
270 toscaInput.setDefaultp(propertyConvertor.convertToToscaObject(input, inputValue, dataTypes, false));
272 toscaInput.setDefaultp(propertyConvertor
273 .convertToToscaObject(input, getInputValue(input.getToscaDefaultValue()),
276 toscaInputs.put(input.getName(), toscaInput);
278 toscaOperation.setInputs(toscaInputs);
281 private static String getInputValue(String inputValue) {
282 String toscaInputValue = inputValue;
283 if (Objects.nonNull(inputValue) && inputValue.contains(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName())) {
284 Gson gson = new Gson();
285 Map<String, List<String>> consumptionValue = gson.fromJson(inputValue, Map.class);
286 List<String> mappedOutputValue =
287 consumptionValue.get(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName());
288 //Extract the interface name from the interface type
289 String interfaceType = mappedOutputValue.get(1);
290 String interfaceName = interfaceType.substring(interfaceType.lastIndexOf('.') + 1);
291 mappedOutputValue.remove(1);
292 mappedOutputValue.add(1, interfaceName);
293 toscaInputValue = gson.toJson(consumptionValue);
295 return toscaInputValue;
298 private static String getInterfaceType(Component component, String interfaceType) {
299 if (LOCAL_INTERFACE_TYPE.equals(interfaceType)) {
300 return DERIVED_FROM_BASE_DEFAULT
301 + component.getComponentMetadataDefinition()
302 .getMetadataDataDefinition().getSystemName();
305 return interfaceType;
308 private static Map<String, Object> getObjectAsMap(Object obj) {
309 ObjectMapper objectMapper = new ObjectMapper();
310 if (obj instanceof ToscaInterfaceDefinition) {
311 //Prevent empty field serialization in interface definition
312 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
314 Map<String, Object> objectAsMap =
315 obj instanceof Map ? (Map<String, Object>) obj : objectMapper.convertValue(obj, Map.class);
317 if (objectAsMap.containsKey(DEFAULT)) {
318 Object defaultValue = objectAsMap.get(DEFAULT);
319 objectAsMap.remove(DEFAULT);
320 objectAsMap.put(DEFAULT_HAS_UNDERSCORE, defaultValue);