2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2020 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
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.
16 * SPDX-License-Identifier: Apache-2.0
17 * ============LICENSE_END=========================================================
19 package org.openecomp.sdc.be.components.impl;
21 import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.QUOTE;
22 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT;
23 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DESCRIPTION;
24 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.IMPLEMENTATION;
25 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS;
26 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.NOTIFICATIONS;
27 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS;
28 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.REQUIRED;
29 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.STATUS;
30 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.TYPE;
32 import com.google.gson.Gson;
33 import fj.data.Either;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collections;
37 import java.util.LinkedHashMap;
38 import java.util.List;
40 import java.util.Map.Entry;
41 import java.util.Optional;
42 import java.util.UUID;
43 import java.util.stream.Collectors;
44 import org.apache.commons.collections.MapUtils;
45 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
46 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
47 import org.openecomp.sdc.be.dao.api.ActionStatus;
48 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
49 import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition;
50 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
51 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
52 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
53 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
54 import org.openecomp.sdc.be.model.InputDefinition;
55 import org.openecomp.sdc.be.model.InterfaceDefinition;
56 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
57 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
58 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
59 import org.openecomp.sdc.exception.ResponseFormat;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62 import org.springframework.stereotype.Component;
65 * Handles interface definition TOSCA conversions
67 @Component("interfaceDefinitionHandler")
68 public class InterfaceDefinitionHandler {
70 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceDefinitionHandler.class);
71 private static final String WITH_ATTRIBUTE = "with attribute '{}': '{}'";
72 private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic;
74 public InterfaceDefinitionHandler(final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic) {
75 this.interfaceOperationBusinessLogic = interfaceOperationBusinessLogic;
79 * Creates an interface definition based on a TOSCA map representing an interface definition.
81 * @param interfaceDefinitionToscaMap the TOSCA interface definition structure
82 * @return an interface definition representation
84 public InterfaceDefinition create(final Map<String, Object> interfaceDefinitionToscaMap, final String model) {
85 final InterfaceDefinition interfaceDefinition = new InterfaceDefinition();
86 interfaceDefinition.setModel(model);
87 if (interfaceDefinitionToscaMap.containsKey(TYPE.getElementName())) {
88 final Object typeObj = interfaceDefinitionToscaMap.get(TYPE.getElementName());
89 if (!(typeObj instanceof String)) {
90 throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML);
92 final String type = (String) typeObj;
93 interfaceDefinition.setType(type);
94 interfaceDefinition.setUniqueId(type);
96 final Map<String, InputDefinition> inputDefinitionMap = handleInputs(interfaceDefinitionToscaMap);
97 if (!inputDefinitionMap.isEmpty()) {
98 final Map<String, InputDataDefinition> collect = inputDefinitionMap.entrySet().stream()
99 .collect(Collectors.toMap(Entry::getKey, value -> new InputDataDefinition(value.getValue())));
100 interfaceDefinition.setInputs(collect);
102 final Map<String, OperationDataDefinition> operationMap;
103 if (interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName()) || interfaceDefinitionToscaMap
104 .containsKey(NOTIFICATIONS.getElementName())) {
105 operationMap = handleOperations(interfaceDefinitionToscaMap);
106 //TODO handle notifications
108 operationMap = handleLegacyOperations(interfaceDefinitionToscaMap);
110 if (!operationMap.isEmpty()) {
111 validateOperations(interfaceDefinition.getType(), operationMap, model);
112 interfaceDefinition.setOperations(operationMap);
114 return interfaceDefinition;
117 private void validateOperations(final String interfaceType, final Map<String, OperationDataDefinition> operationMap, final String model) {
118 if (MapUtils.isEmpty(operationMap)) {
121 Either<Map<String, InterfaceDefinition>, ResponseFormat> interfaceDefinitionMapEither = interfaceOperationBusinessLogic
122 .getAllInterfaceLifecycleTypes(model);
123 if (interfaceDefinitionMapEither.isRight() || MapUtils.isEmpty(interfaceDefinitionMapEither.left().value())) {
124 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
126 final Map<String, InterfaceDefinition> interfaceDefinitionMap = interfaceDefinitionMapEither.left().value();
127 final Optional<InterfaceDefinition> interfaceDefinitionOptional = interfaceDefinitionMap.entrySet().stream()
128 .filter(interfaceDefinitionEntry -> interfaceDefinitionEntry.getKey().equalsIgnoreCase(UniqueIdBuilder.buildInterfaceTypeUid(model, interfaceType))).map(Entry::getValue).findFirst();
129 if (interfaceDefinitionOptional.isEmpty()) {
130 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
132 final InterfaceDefinition interfaceDefinition = interfaceDefinitionOptional.get();
133 operationMap.keySet().forEach(operation1 -> {
134 if (!interfaceDefinition.hasOperation(operation1)) {
135 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_OPERATION_NOT_DEFINED, operation1, interfaceType);
140 private Map<String, OperationDataDefinition> handleOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
141 if (!interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName())) {
142 return Collections.emptyMap();
144 final Map<String, Object> operationMap = (Map<String, Object>) interfaceDefinitionToscaMap.get(OPERATIONS.getElementName());
145 return operationMap.entrySet().stream()
146 .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
147 .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
150 private Map<String, OperationDataDefinition> handleLegacyOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
151 final List<String> notALegacyOperationEntry = Arrays
152 .asList(OPERATIONS.getElementName(), TYPE.getElementName(), INPUTS.getElementName(), NOTIFICATIONS.getElementName());
153 return interfaceDefinitionToscaMap.entrySet().stream().filter(interfaceEntry -> !notALegacyOperationEntry.contains(interfaceEntry.getKey()))
154 .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
155 .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
158 private OperationDataDefinition createOperation(final String operationName, final Map<String, Object> operationDefinitionMap) {
159 final OperationDataDefinition operation = new OperationDataDefinition();
160 operation.setUniqueId(UUID.randomUUID().toString());
161 operation.setName(operationName);
163 if (MapUtils.isEmpty(operationDefinitionMap)) {
166 Object operationDescription = operationDefinitionMap.get(
167 DESCRIPTION.getElementName()
169 if (null != operationDescription) {
170 operation.setDescription(operationDescription.toString());
172 operation.setImplementation(handleOperationImplementation(operationDefinitionMap).orElse(new ArtifactDataDefinition()));
173 if (operationDefinitionMap.containsKey(INPUTS.getElementName())) {
174 final Map<String, Object> interfaceInputs = (Map<String, Object>) operationDefinitionMap.get(INPUTS.getElementName());
175 operation.setInputs(handleInterfaceOperationInputs(interfaceInputs));
180 private ListDataDefinition<OperationInputDefinition> handleInterfaceOperationInputs(final Map<String, Object> interfaceInputs) {
181 final ListDataDefinition<OperationInputDefinition> inputs = new ListDataDefinition<>();
182 for (final Entry<String, Object> interfaceInput : interfaceInputs.entrySet()) {
183 final OperationInputDefinition operationInput = new OperationInputDefinition();
184 operationInput.setUniqueId(UUID.randomUUID().toString());
185 operationInput.setInputId(operationInput.getUniqueId());
186 operationInput.setName(interfaceInput.getKey());
187 handleInputToscaDefinition(interfaceInput.getKey(), interfaceInput.getValue(), operationInput);
188 inputs.add(operationInput);
193 private void handleInputToscaDefinition(final String inputName, final Object value, final OperationInputDefinition operationInput) {
194 if (value instanceof Map) {
195 final LinkedHashMap<String, Object> inputPropertyValue = (LinkedHashMap<String, Object>) value;
196 LOGGER.debug("Creating interface operation input '{}'", inputName);
197 if (inputPropertyValue.get(TYPE.getElementName()) != null) {
198 final String type = inputPropertyValue.get(TYPE.getElementName()).toString();
199 LOGGER.debug(WITH_ATTRIBUTE, TYPE.getElementName(), type);
200 operationInput.setType(type);
202 if (inputPropertyValue.get(DESCRIPTION.getElementName()) != null) {
203 final String description = inputPropertyValue.get(DESCRIPTION.getElementName()).toString();
204 LOGGER.debug(WITH_ATTRIBUTE, DESCRIPTION.getElementName(), description);
205 operationInput.setDescription(description);
207 if (inputPropertyValue.get(REQUIRED.getElementName()) != null) {
208 final boolean required = Boolean.parseBoolean(inputPropertyValue.get(REQUIRED.getElementName()).toString());
209 LOGGER.debug(WITH_ATTRIBUTE, REQUIRED.getElementName(), required);
210 operationInput.setRequired(required);
212 if (inputPropertyValue.get(DEFAULT.getElementName()) != null) {
213 final Gson gson = new Gson();
214 final String json = gson.toJson(inputPropertyValue.get(DEFAULT.getElementName()));
215 LOGGER.debug(WITH_ATTRIBUTE, DEFAULT.getElementName(), json);
216 operationInput.setToscaDefaultValue(json);
218 if (inputPropertyValue.get(STATUS.getElementName()) != null) {
219 final String status = inputPropertyValue.get(STATUS.getElementName()).toString();
220 LOGGER.debug(WITH_ATTRIBUTE, STATUS.getElementName(), status);
221 operationInput.setStatus(status);
225 if (value instanceof String) {
226 final String stringValue = (String) value;
227 operationInput.setDefaultValue(stringValue);
228 operationInput.setToscaDefaultValue(stringValue);
229 operationInput.setValue(stringValue);
233 @SuppressWarnings("unchecked")
234 private Optional<ArtifactDataDefinition> handleOperationImplementation(final Map<String, Object> operationDefinitionMap) {
235 if (!operationDefinitionMap.containsKey(IMPLEMENTATION.getElementName())) {
236 return Optional.empty();
238 final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition();
239 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof Map &&
240 ((Map)operationDefinitionMap.get(IMPLEMENTATION.getElementName())).containsKey("primary")) {
241 Map<String, Object> implDetails = (Map) ((Map)operationDefinitionMap.get(IMPLEMENTATION.getElementName())).get("primary");
243 if (implDetails.get("file") != null) {
244 final String file = implDetails.get("file").toString();
245 artifactDataDefinition.setArtifactName(generateArtifactName(file));
247 if (implDetails.get("type") != null) {
248 artifactDataDefinition.setArtifactType(implDetails.get("type").toString());
250 if (implDetails.get("artifact_version") != null) {
251 artifactDataDefinition.setArtifactVersion(implDetails.get("artifact_version").toString());
254 if(implDetails.get("properties") instanceof Map) {
255 List<PropertyDataDefinition> operationProperties = artifactDataDefinition.getProperties() == null ? new ArrayList<>() : artifactDataDefinition.getProperties();
256 Map<String, Object> properties = (Map<String, Object>) implDetails.get("properties");
257 properties.forEach((k,v) -> {
258 ToscaPropertyType type = getTypeFromObject(v);
260 PropertyDataDefinition propertyDef = new PropertyDataDefinition();
261 propertyDef.setName(k);
262 propertyDef.setType(type.getType());
263 propertyDef.setValue(v.toString());
264 artifactDataDefinition.addProperty(propertyDef);
269 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof String) {
270 final String implementation = (String) operationDefinitionMap.get(IMPLEMENTATION.getElementName());
271 artifactDataDefinition.setArtifactName(generateArtifactName(implementation));
273 return Optional.of(artifactDataDefinition);
276 private String generateArtifactName(final String name) {
277 if (OperationArtifactUtil.artifactNameIsALiteralValue(name)) {
280 return QUOTE + name + QUOTE;
284 private ToscaPropertyType getTypeFromObject(final Object value) {
285 if (value instanceof String) {
286 return ToscaPropertyType.STRING;
288 if (value instanceof Integer) {
289 return ToscaPropertyType.INTEGER;
291 if (value instanceof Boolean) {
292 return ToscaPropertyType.BOOLEAN;
294 if (value instanceof Float || value instanceof Double) {
295 return ToscaPropertyType.FLOAT;
301 private Map<String, InputDefinition> handleInputs(final Map<String, Object> interfaceDefinitionToscaMap) {
302 if (!interfaceDefinitionToscaMap.containsKey(INPUTS.getElementName())) {
303 return Collections.emptyMap();
305 final Either<Map<String, InputDefinition>, ResultStatusEnum> inputMapEither = ImportUtils.getInputs(interfaceDefinitionToscaMap);
306 if (inputMapEither.isRight()) {
307 return Collections.emptyMap();
309 return inputMapEither.left().value();