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);
162 operation.setImplementation(handleOperationImplementation(operationDefinitionMap).orElse(new ArtifactDataDefinition()));
163 if (operationDefinitionMap.containsKey(INPUTS.getElementName())) {
164 final Map<String, Object> interfaceInputs = (Map<String, Object>) operationDefinitionMap.get(INPUTS.getElementName());
165 operation.setInputs(handleInterfaceOperationInputs(interfaceInputs));
170 private ListDataDefinition<OperationInputDefinition> handleInterfaceOperationInputs(final Map<String, Object> interfaceInputs) {
171 final ListDataDefinition<OperationInputDefinition> inputs = new ListDataDefinition<>();
172 for (final Entry<String, Object> interfaceInput : interfaceInputs.entrySet()) {
173 final OperationInputDefinition operationInput = new OperationInputDefinition();
174 operationInput.setUniqueId(UUID.randomUUID().toString());
175 operationInput.setInputId(operationInput.getUniqueId());
176 operationInput.setName(interfaceInput.getKey());
177 handleInputToscaDefinition(interfaceInput.getKey(), interfaceInput.getValue(), operationInput);
178 inputs.add(operationInput);
183 private void handleInputToscaDefinition(final String inputName, final Object value, final OperationInputDefinition operationInput) {
184 if (value instanceof Map) {
185 final LinkedHashMap<String, Object> inputPropertyValue = (LinkedHashMap<String, Object>) value;
186 LOGGER.debug("Creating interface operation input '{}'", inputName);
187 if (inputPropertyValue.get(TYPE.getElementName()) != null) {
188 final String type = inputPropertyValue.get(TYPE.getElementName()).toString();
189 LOGGER.debug(WITH_ATTRIBUTE, TYPE.getElementName(), type);
190 operationInput.setType(type);
192 if (inputPropertyValue.get(DESCRIPTION.getElementName()) != null) {
193 final String description = inputPropertyValue.get(DESCRIPTION.getElementName()).toString();
194 LOGGER.debug(WITH_ATTRIBUTE, DESCRIPTION.getElementName(), description);
195 operationInput.setDescription(description);
197 if (inputPropertyValue.get(REQUIRED.getElementName()) != null) {
198 final boolean required = Boolean.parseBoolean(inputPropertyValue.get(REQUIRED.getElementName()).toString());
199 LOGGER.debug(WITH_ATTRIBUTE, REQUIRED.getElementName(), required);
200 operationInput.setRequired(required);
202 if (inputPropertyValue.get(DEFAULT.getElementName()) != null) {
203 final Gson gson = new Gson();
204 final String json = gson.toJson(inputPropertyValue.get(DEFAULT.getElementName()));
205 LOGGER.debug(WITH_ATTRIBUTE, DEFAULT.getElementName(), json);
206 operationInput.setToscaDefaultValue(json);
208 if (inputPropertyValue.get(STATUS.getElementName()) != null) {
209 final String status = inputPropertyValue.get(STATUS.getElementName()).toString();
210 LOGGER.debug(WITH_ATTRIBUTE, STATUS.getElementName(), status);
211 operationInput.setStatus(status);
215 if (value instanceof String) {
216 final String stringValue = (String) value;
217 operationInput.setDefaultValue(stringValue);
218 operationInput.setToscaDefaultValue(stringValue);
219 operationInput.setValue(stringValue);
223 @SuppressWarnings("unchecked")
224 private Optional<ArtifactDataDefinition> handleOperationImplementation(final Map<String, Object> operationDefinitionMap) {
225 if (!operationDefinitionMap.containsKey(IMPLEMENTATION.getElementName())) {
226 return Optional.empty();
228 final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition();
229 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof Map &&
230 ((Map)operationDefinitionMap.get(IMPLEMENTATION.getElementName())).containsKey("primary")) {
231 Map<String, Object> implDetails = (Map) ((Map)operationDefinitionMap.get(IMPLEMENTATION.getElementName())).get("primary");
233 if (implDetails.get("file") != null) {
234 final String file = implDetails.get("file").toString();
235 artifactDataDefinition.setArtifactName(generateArtifactName(file));
237 if (implDetails.get("type") != null) {
238 artifactDataDefinition.setArtifactType(implDetails.get("type").toString());
240 if (implDetails.get("artifact_version") != null) {
241 artifactDataDefinition.setArtifactVersion(implDetails.get("artifact_version").toString());
244 if(implDetails.get("properties") instanceof Map) {
245 List<PropertyDataDefinition> operationProperties = artifactDataDefinition.getProperties() == null ? new ArrayList<>() : artifactDataDefinition.getProperties();
246 Map<String, Object> properties = (Map<String, Object>) implDetails.get("properties");
247 properties.forEach((k,v) -> {
248 ToscaPropertyType type = getTypeFromObject(v);
250 PropertyDataDefinition propertyDef = new PropertyDataDefinition();
251 propertyDef.setName(k);
252 propertyDef.setType(type.getType());
253 propertyDef.setValue(v.toString());
254 artifactDataDefinition.addProperty(propertyDef);
259 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof String) {
260 final String implementation = (String) operationDefinitionMap.get(IMPLEMENTATION.getElementName());
261 artifactDataDefinition.setArtifactName(generateArtifactName(implementation));
263 return Optional.of(artifactDataDefinition);
266 private String generateArtifactName(final String name) {
267 if (OperationArtifactUtil.artifactNameIsALiteralValue(name)) {
270 return QUOTE + name + QUOTE;
274 private ToscaPropertyType getTypeFromObject(final Object value) {
275 if (value instanceof String) {
276 return ToscaPropertyType.STRING;
278 if (value instanceof Integer) {
279 return ToscaPropertyType.INTEGER;
281 if (value instanceof Boolean) {
282 return ToscaPropertyType.BOOLEAN;
284 if (value instanceof Float || value instanceof Double) {
285 return ToscaPropertyType.FLOAT;
291 private Map<String, InputDefinition> handleInputs(final Map<String, Object> interfaceDefinitionToscaMap) {
292 if (!interfaceDefinitionToscaMap.containsKey(INPUTS.getElementName())) {
293 return Collections.emptyMap();
295 final Either<Map<String, InputDefinition>, ResultStatusEnum> inputMapEither = ImportUtils.getInputs(interfaceDefinitionToscaMap);
296 if (inputMapEither.isRight()) {
297 return Collections.emptyMap();
299 return inputMapEither.left().value();