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=========================================================
20 package org.openecomp.sdc.be.components.impl;
22 import static org.openecomp.sdc.be.components.impl.ImportUtils.Constants.QUOTE;
23 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.ACTIVITIES;
24 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT;
25 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DESCRIPTION;
26 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.IMPLEMENTATION;
27 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS;
28 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.MILESTONES;
29 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.NOTIFICATIONS;
30 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS;
31 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.REQUIRED;
32 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.STATUS;
33 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.TYPE;
34 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.WORKFLOW;
36 import com.google.gson.Gson;
37 import fj.data.Either;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.LinkedHashMap;
43 import java.util.List;
45 import java.util.Map.Entry;
46 import java.util.Optional;
47 import java.util.UUID;
48 import java.util.stream.Collectors;
49 import org.apache.commons.collections.MapUtils;
50 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
51 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
52 import org.openecomp.sdc.be.dao.api.ActionStatus;
53 import org.openecomp.sdc.be.datatypes.elements.ActivityDataDefinition;
54 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
55 import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition;
56 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
57 import org.openecomp.sdc.be.datatypes.elements.MilestoneDataDefinition;
58 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
59 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
60 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
61 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
62 import org.openecomp.sdc.be.model.InputDefinition;
63 import org.openecomp.sdc.be.model.InterfaceDefinition;
64 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
65 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
66 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
67 import org.openecomp.sdc.exception.ResponseFormat;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70 import org.springframework.stereotype.Component;
73 * Handles interface definition TOSCA conversions
75 @Component("interfaceDefinitionHandler")
76 public class InterfaceDefinitionHandler {
78 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceDefinitionHandler.class);
79 private static final String WITH_ATTRIBUTE = "with attribute '{}': '{}'";
80 private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic;
82 public InterfaceDefinitionHandler(final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic) {
83 this.interfaceOperationBusinessLogic = interfaceOperationBusinessLogic;
87 * Creates an interface definition based on a TOSCA map representing an interface definition.
89 * @param interfaceDefinitionToscaMap the TOSCA interface definition structure
90 * @return an interface definition representation
92 public InterfaceDefinition create(final Map<String, Object> interfaceDefinitionToscaMap, final String model) {
93 final InterfaceDefinition interfaceDefinition = new InterfaceDefinition();
94 interfaceDefinition.setModel(model);
95 if (interfaceDefinitionToscaMap.containsKey(TYPE.getElementName())) {
96 final Object typeObj = interfaceDefinitionToscaMap.get(TYPE.getElementName());
97 if (!(typeObj instanceof String)) {
98 throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML);
100 final String type = (String) typeObj;
101 interfaceDefinition.setType(type);
102 interfaceDefinition.setUniqueId(type);
104 final Map<String, InputDefinition> inputDefinitionMap = handleInputs(interfaceDefinitionToscaMap);
105 if (!inputDefinitionMap.isEmpty()) {
106 final Map<String, InputDataDefinition> collect = inputDefinitionMap.entrySet().stream()
107 .collect(Collectors.toMap(Entry::getKey, value -> new InputDataDefinition(value.getValue())));
108 interfaceDefinition.setInputs(collect);
110 final Map<String, OperationDataDefinition> operationMap;
111 if (interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName()) || interfaceDefinitionToscaMap
112 .containsKey(NOTIFICATIONS.getElementName())) {
113 operationMap = handleOperations(interfaceDefinitionToscaMap);
114 //TODO handle notifications
116 operationMap = handleLegacyOperations(interfaceDefinitionToscaMap);
118 if (!operationMap.isEmpty()) {
119 validateOperations(interfaceDefinition.getType(), operationMap, model);
120 interfaceDefinition.setOperations(operationMap);
122 return interfaceDefinition;
125 private void validateOperations(final String interfaceType, final Map<String, OperationDataDefinition> operationMap, final String model) {
126 if (MapUtils.isEmpty(operationMap)) {
129 Either<Map<String, InterfaceDefinition>, ResponseFormat> interfaceDefinitionMapEither = interfaceOperationBusinessLogic
130 .getAllInterfaceLifecycleTypes(model);
131 if (interfaceDefinitionMapEither.isRight() || MapUtils.isEmpty(interfaceDefinitionMapEither.left().value())) {
132 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
134 final Map<String, InterfaceDefinition> interfaceDefinitionMap = interfaceDefinitionMapEither.left().value();
135 final Optional<InterfaceDefinition> interfaceDefinitionOptional = interfaceDefinitionMap.entrySet().stream()
136 .filter(interfaceDefinitionEntry -> interfaceDefinitionEntry.getKey()
137 .equalsIgnoreCase(UniqueIdBuilder.buildInterfaceTypeUid(model, interfaceType))).map(Entry::getValue).findFirst();
138 if (interfaceDefinitionOptional.isEmpty()) {
139 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
141 final InterfaceDefinition interfaceDefinition = interfaceDefinitionOptional.get();
142 operationMap.keySet().forEach(operation1 -> {
143 if (!interfaceDefinition.hasOperation(operation1)) {
144 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_OPERATION_NOT_DEFINED, operation1, interfaceType);
149 private Map<String, OperationDataDefinition> handleOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
150 if (!interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName())) {
151 return Collections.emptyMap();
153 final Map<String, Object> operationMap = (Map<String, Object>) interfaceDefinitionToscaMap.get(OPERATIONS.getElementName());
154 return operationMap.entrySet().stream()
155 .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
156 .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
159 private Map<String, OperationDataDefinition> handleLegacyOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
160 final List<String> notALegacyOperationEntry = Arrays
161 .asList(OPERATIONS.getElementName(), TYPE.getElementName(), INPUTS.getElementName(), NOTIFICATIONS.getElementName());
162 return interfaceDefinitionToscaMap.entrySet().stream().filter(interfaceEntry -> !notALegacyOperationEntry.contains(interfaceEntry.getKey()))
163 .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
164 .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
167 private OperationDataDefinition createOperation(final String operationName, final Map<String, Object> operationDefinitionMap) {
168 final OperationDataDefinition operation = new OperationDataDefinition();
169 operation.setUniqueId(UUID.randomUUID().toString());
170 operation.setName(operationName);
172 if (MapUtils.isEmpty(operationDefinitionMap)) {
175 Object operationDescription = operationDefinitionMap.get(DESCRIPTION.getElementName());
176 if (null != operationDescription) {
177 operation.setDescription(operationDescription.toString());
179 operation.setImplementation(handleOperationImplementation(operationDefinitionMap).orElse(new ArtifactDataDefinition()));
180 if (operationDefinitionMap.containsKey(INPUTS.getElementName())) {
181 final Map<String, Object> interfaceInputs = (Map<String, Object>) operationDefinitionMap.get(INPUTS.getElementName());
182 operation.setInputs(handleInterfaceOperationInputs(interfaceInputs));
184 if (operationDefinitionMap.containsKey(MILESTONES.getElementName())) {
185 final Map<String, Object> interfaceMilestones = (Map<String, Object>) operationDefinitionMap.get(MILESTONES.getElementName());
186 operation.setMilestones(handleInterfaceOperationMilestones(interfaceMilestones));
191 private Map<String, MilestoneDataDefinition> handleInterfaceOperationMilestones(final Map<String, Object> interfaceMilestones) {
192 final Map<String, MilestoneDataDefinition> milestones = new HashMap<>();
193 for (final Entry<String, Object> interfaceInput : interfaceMilestones.entrySet()) {
194 final MilestoneDataDefinition operationMilestone = new MilestoneDataDefinition();
195 ListDataDefinition<ActivityDataDefinition> activities = handleMilestoneActivities(interfaceInput.getValue());
196 if (activities.isEmpty()) {
197 throw new ByActionStatusComponentException(ActionStatus.INVALID_OPERATION_MILESTONE, interfaceInput.getKey());
199 operationMilestone.setActivities(activities);
200 milestones.put(interfaceInput.getKey(), operationMilestone);
205 private ListDataDefinition<ActivityDataDefinition> handleMilestoneActivities(final Object value) {
206 ListDataDefinition<ActivityDataDefinition> activities = new ListDataDefinition<>();
207 if (value instanceof Map) {
208 final LinkedHashMap<String, Object> activitiesValue = (LinkedHashMap<String, Object>) value;
209 if (activitiesValue.containsKey(ACTIVITIES.getElementName())) {
210 final List<Object> milestoneActivities = (List<Object>) activitiesValue.get(ACTIVITIES.getElementName());
211 for (Object activityValue : milestoneActivities) {
212 ActivityDataDefinition activity = new ActivityDataDefinition();
213 if (activityValue instanceof Map) {
214 Map<String, String> activityMap = (Map<String, String>) activityValue;
215 if (activityMap.containsKey(TYPE.getElementName()) && activityMap.containsKey(WORKFLOW.getElementName())) {
216 activity.setType(activityMap.get(TYPE.getElementName()));
217 activity.setWorkflow(activityMap.get(WORKFLOW.getElementName()));
218 activities.add(activity);
220 return new ListDataDefinition<>();
223 return new ListDataDefinition<>();
227 return new ListDataDefinition<>();
233 private ListDataDefinition<OperationInputDefinition> handleInterfaceOperationInputs(final Map<String, Object> interfaceInputs) {
234 final ListDataDefinition<OperationInputDefinition> inputs = new ListDataDefinition<>();
235 for (final Entry<String, Object> interfaceInput : interfaceInputs.entrySet()) {
236 final OperationInputDefinition operationInput = new OperationInputDefinition();
237 operationInput.setUniqueId(UUID.randomUUID().toString());
238 operationInput.setInputId(operationInput.getUniqueId());
239 operationInput.setName(interfaceInput.getKey());
240 handleInputToscaDefinition(interfaceInput.getKey(), interfaceInput.getValue(), operationInput);
241 inputs.add(operationInput);
246 private void handleInputToscaDefinition(final String inputName, final Object value, final OperationInputDefinition operationInput) {
247 if (value instanceof Map) {
248 final LinkedHashMap<String, Object> inputPropertyValue = (LinkedHashMap<String, Object>) value;
249 LOGGER.debug("Creating interface operation input '{}'", inputName);
250 if (inputPropertyValue.get(TYPE.getElementName()) != null) {
251 final String type = inputPropertyValue.get(TYPE.getElementName()).toString();
252 LOGGER.debug(WITH_ATTRIBUTE, TYPE.getElementName(), type);
253 operationInput.setType(type);
255 if (inputPropertyValue.get(DESCRIPTION.getElementName()) != null) {
256 final String description = inputPropertyValue.get(DESCRIPTION.getElementName()).toString();
257 LOGGER.debug(WITH_ATTRIBUTE, DESCRIPTION.getElementName(), description);
258 operationInput.setDescription(description);
260 if (inputPropertyValue.get(REQUIRED.getElementName()) != null) {
261 final boolean required = Boolean.parseBoolean(inputPropertyValue.get(REQUIRED.getElementName()).toString());
262 LOGGER.debug(WITH_ATTRIBUTE, REQUIRED.getElementName(), required);
263 operationInput.setRequired(required);
265 if (inputPropertyValue.get(DEFAULT.getElementName()) != null) {
266 final Gson gson = new Gson();
267 final String json = gson.toJson(inputPropertyValue.get(DEFAULT.getElementName()));
268 LOGGER.debug(WITH_ATTRIBUTE, DEFAULT.getElementName(), json);
269 operationInput.setToscaDefaultValue(json);
271 if (inputPropertyValue.get(STATUS.getElementName()) != null) {
272 final String status = inputPropertyValue.get(STATUS.getElementName()).toString();
273 LOGGER.debug(WITH_ATTRIBUTE, STATUS.getElementName(), status);
274 operationInput.setStatus(status);
278 if (value instanceof String) {
279 final String stringValue = (String) value;
280 operationInput.setDefaultValue(stringValue);
281 operationInput.setToscaDefaultValue(stringValue);
282 operationInput.setValue(stringValue);
286 @SuppressWarnings("unchecked")
287 private Optional<ArtifactDataDefinition> handleOperationImplementation(final Map<String, Object> operationDefinitionMap) {
288 if (!operationDefinitionMap.containsKey(IMPLEMENTATION.getElementName())) {
289 return Optional.empty();
291 final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition();
292 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof Map &&
293 ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).containsKey("primary")) {
294 Map<String, Object> implDetails = (Map) ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).get("primary");
296 if (implDetails.get("file") != null) {
297 final String file = implDetails.get("file").toString();
298 artifactDataDefinition.setArtifactName(generateArtifactName(file));
300 if (implDetails.get("type") != null) {
301 artifactDataDefinition.setArtifactType(implDetails.get("type").toString());
303 if (implDetails.get("artifact_version") != null) {
304 artifactDataDefinition.setArtifactVersion(implDetails.get("artifact_version").toString());
307 if (implDetails.get("properties") instanceof Map) {
308 List<PropertyDataDefinition> operationProperties =
309 artifactDataDefinition.getProperties() == null ? new ArrayList<>() : artifactDataDefinition.getProperties();
310 Map<String, Object> properties = (Map<String, Object>) implDetails.get("properties");
311 properties.forEach((k, v) -> {
312 ToscaPropertyType type = getTypeFromObject(v);
314 PropertyDataDefinition propertyDef = new PropertyDataDefinition();
315 propertyDef.setName(k);
316 propertyDef.setType(type.getType());
317 propertyDef.setValue(v.toString());
318 if (type.equals(ToscaPropertyType.LIST)) {
319 Gson gson = new Gson();
320 propertyDef.setValue(gson.toJson(v));
321 PropertyDataDefinition pdd = new PropertyDataDefinition();
322 pdd.setType("string");
323 SchemaDefinition sd = new SchemaDefinition();
325 propertyDef.setSchema(sd);
327 artifactDataDefinition.addProperty(propertyDef);
333 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof Map &&
334 ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).containsKey("timeout")) {
335 final Object timeOut = ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).get("timeout");
336 artifactDataDefinition.setTimeout((Integer)timeOut);
339 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof String) {
340 final String implementation = (String) operationDefinitionMap.get(IMPLEMENTATION.getElementName());
341 artifactDataDefinition.setArtifactName(generateArtifactName(implementation));
343 return Optional.of(artifactDataDefinition);
346 private String generateArtifactName(final String name) {
347 if (OperationArtifactUtil.artifactNameIsALiteralValue(name)) {
350 return QUOTE + name + QUOTE;
354 private ToscaPropertyType getTypeFromObject(final Object value) {
355 if (value instanceof String) {
356 return ToscaPropertyType.STRING;
358 if (value instanceof Integer) {
359 return ToscaPropertyType.INTEGER;
361 if (value instanceof Boolean) {
362 return ToscaPropertyType.BOOLEAN;
364 if (value instanceof Float || value instanceof Double) {
365 return ToscaPropertyType.FLOAT;
367 if (value instanceof List) {
368 return ToscaPropertyType.LIST;
374 private Map<String, InputDefinition> handleInputs(final Map<String, Object> interfaceDefinitionToscaMap) {
375 if (!interfaceDefinitionToscaMap.containsKey(INPUTS.getElementName())) {
376 return Collections.emptyMap();
378 final Either<Map<String, InputDefinition>, ResultStatusEnum> inputMapEither = ImportUtils.getInputs(interfaceDefinitionToscaMap);
379 if (inputMapEither.isRight()) {
380 return Collections.emptyMap();
382 return inputMapEither.left().value();