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.VALUE;
35 import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.WORKFLOW;
37 import com.google.gson.Gson;
38 import fj.data.Either;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.LinkedHashMap;
44 import java.util.List;
46 import java.util.Map.Entry;
47 import java.util.Optional;
48 import java.util.UUID;
49 import java.util.stream.Collectors;
50 import org.apache.commons.collections.MapUtils;
51 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
52 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
53 import org.openecomp.sdc.be.dao.api.ActionStatus;
54 import org.openecomp.sdc.be.datatypes.elements.ActivityDataDefinition;
55 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
56 import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition;
57 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
58 import org.openecomp.sdc.be.datatypes.elements.MilestoneDataDefinition;
59 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
60 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
61 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
62 import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition;
63 import org.openecomp.sdc.be.model.InputDefinition;
64 import org.openecomp.sdc.be.model.InterfaceDefinition;
65 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
66 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
67 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
68 import org.openecomp.sdc.exception.ResponseFormat;
69 import org.slf4j.Logger;
70 import org.slf4j.LoggerFactory;
71 import org.springframework.stereotype.Component;
74 * Handles interface definition TOSCA conversions
76 @Component("interfaceDefinitionHandler")
77 public class InterfaceDefinitionHandler {
79 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceDefinitionHandler.class);
80 private static final String WITH_ATTRIBUTE = "with attribute '{}': '{}'";
81 private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic;
83 public InterfaceDefinitionHandler(final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic) {
84 this.interfaceOperationBusinessLogic = interfaceOperationBusinessLogic;
88 * Creates an interface definition based on a TOSCA map representing an interface definition.
90 * @param interfaceDefinitionToscaMap the TOSCA interface definition structure
91 * @return an interface definition representation
93 public InterfaceDefinition create(final Map<String, Object> interfaceDefinitionToscaMap, final String model) {
94 final InterfaceDefinition interfaceDefinition = new InterfaceDefinition();
95 interfaceDefinition.setModel(model);
96 if (interfaceDefinitionToscaMap.containsKey(TYPE.getElementName())) {
97 final Object typeObj = interfaceDefinitionToscaMap.get(TYPE.getElementName());
98 if (!(typeObj instanceof String)) {
99 throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML);
101 final String type = (String) typeObj;
102 interfaceDefinition.setType(type);
103 interfaceDefinition.setUniqueId(type);
105 final Map<String, InputDefinition> inputDefinitionMap = handleInputs(interfaceDefinitionToscaMap);
106 if (!inputDefinitionMap.isEmpty()) {
107 final Map<String, InputDataDefinition> collect = inputDefinitionMap.entrySet().stream()
108 .collect(Collectors.toMap(Entry::getKey, value -> new InputDataDefinition(value.getValue())));
109 interfaceDefinition.setInputs(collect);
111 final Map<String, OperationDataDefinition> operationMap;
112 if (interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName()) || interfaceDefinitionToscaMap
113 .containsKey(NOTIFICATIONS.getElementName())) {
114 operationMap = handleOperations(interfaceDefinitionToscaMap);
115 //TODO handle notifications
117 operationMap = handleLegacyOperations(interfaceDefinitionToscaMap);
119 if (!operationMap.isEmpty()) {
120 validateOperations(interfaceDefinition.getType(), operationMap, model);
121 interfaceDefinition.setOperations(operationMap);
123 return interfaceDefinition;
126 private void validateOperations(final String interfaceType, final Map<String, OperationDataDefinition> operationMap, final String model) {
127 if (MapUtils.isEmpty(operationMap)) {
130 Either<Map<String, InterfaceDefinition>, ResponseFormat> interfaceDefinitionMapEither = interfaceOperationBusinessLogic
131 .getAllInterfaceLifecycleTypes(model);
132 if (interfaceDefinitionMapEither.isRight() || MapUtils.isEmpty(interfaceDefinitionMapEither.left().value())) {
133 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
135 final Map<String, InterfaceDefinition> interfaceDefinitionMap = interfaceDefinitionMapEither.left().value();
136 final Optional<InterfaceDefinition> interfaceDefinitionOptional = interfaceDefinitionMap.entrySet().stream()
137 .filter(interfaceDefinitionEntry -> interfaceDefinitionEntry.getKey()
138 .equalsIgnoreCase(UniqueIdBuilder.buildInterfaceTypeUid(model, interfaceType))).map(Entry::getValue).findFirst();
139 if (interfaceDefinitionOptional.isEmpty()) {
140 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
142 final InterfaceDefinition interfaceDefinition = interfaceDefinitionOptional.get();
143 operationMap.keySet().forEach(operation1 -> {
144 if (!interfaceDefinition.hasOperation(operation1)) {
145 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_OPERATION_NOT_DEFINED, operation1, interfaceType);
150 private Map<String, OperationDataDefinition> handleOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
151 if (!interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName())) {
152 return Collections.emptyMap();
154 final Map<String, Object> operationMap = (Map<String, Object>) interfaceDefinitionToscaMap.get(OPERATIONS.getElementName());
155 return operationMap.entrySet().stream()
156 .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
157 .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
160 private Map<String, OperationDataDefinition> handleLegacyOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
161 final List<String> notALegacyOperationEntry = Arrays
162 .asList(OPERATIONS.getElementName(), TYPE.getElementName(), INPUTS.getElementName(), NOTIFICATIONS.getElementName());
163 return interfaceDefinitionToscaMap.entrySet().stream().filter(interfaceEntry -> !notALegacyOperationEntry.contains(interfaceEntry.getKey()))
164 .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
165 .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
168 private OperationDataDefinition createOperation(final String operationName, final Map<String, Object> operationDefinitionMap) {
169 final OperationDataDefinition operation = new OperationDataDefinition();
170 operation.setUniqueId(UUID.randomUUID().toString());
171 operation.setName(operationName);
173 if (MapUtils.isEmpty(operationDefinitionMap)) {
176 Object operationDescription = operationDefinitionMap.get(DESCRIPTION.getElementName());
177 if (null != operationDescription) {
178 operation.setDescription(operationDescription.toString());
180 operation.setImplementation(handleOperationImplementation(operationDefinitionMap).orElse(new ArtifactDataDefinition()));
181 if (operationDefinitionMap.containsKey(INPUTS.getElementName())) {
182 final Map<String, Object> interfaceInputs = (Map<String, Object>) operationDefinitionMap.get(INPUTS.getElementName());
183 operation.setInputs(handleInterfaceOperationInputs(interfaceInputs));
185 if (operationDefinitionMap.containsKey(MILESTONES.getElementName())) {
186 final Map<String, Object> interfaceMilestones = (Map<String, Object>) operationDefinitionMap.get(MILESTONES.getElementName());
187 operation.setMilestones(handleInterfaceOperationMilestones(interfaceMilestones));
192 private Map<String, MilestoneDataDefinition> handleInterfaceOperationMilestones(final Map<String, Object> interfaceMilestones) {
193 final Map<String, MilestoneDataDefinition> milestones = new HashMap<>();
194 for (final Entry<String, Object> interfaceInput : interfaceMilestones.entrySet()) {
195 final MilestoneDataDefinition operationMilestone = new MilestoneDataDefinition();
196 ListDataDefinition<ActivityDataDefinition> activities = handleMilestoneActivities(interfaceInput.getValue());
197 if (activities.isEmpty()) {
198 throw new ByActionStatusComponentException(ActionStatus.INVALID_OPERATION_MILESTONE, interfaceInput.getKey());
200 operationMilestone.setActivities(activities);
201 milestones.put(interfaceInput.getKey(), operationMilestone);
206 private ListDataDefinition<ActivityDataDefinition> handleMilestoneActivities(final Object value) {
207 ListDataDefinition<ActivityDataDefinition> activities = new ListDataDefinition<>();
208 if (value instanceof Map) {
209 final LinkedHashMap<String, Object> activitiesValue = (LinkedHashMap<String, Object>) value;
210 if (activitiesValue.containsKey(ACTIVITIES.getElementName())) {
211 final List<Object> milestoneActivities = (List<Object>) activitiesValue.get(ACTIVITIES.getElementName());
212 for (Object activityValue : milestoneActivities) {
213 ActivityDataDefinition activity = new ActivityDataDefinition();
214 if (activityValue instanceof Map) {
215 Map<String, Object> activityMap = (Map<String, Object>) activityValue;
216 if (activityMap.containsKey(INPUTS.getElementName())) {
217 activity.setInputs(handleInterfaceOperationInputs((Map<String, Object>) activityMap.get(INPUTS.getElementName())));
219 if (activityMap.containsKey(TYPE.getElementName()) && activityMap.containsKey(WORKFLOW.getElementName())) {
220 activity.setType((String) activityMap.get(TYPE.getElementName()));
221 activity.setWorkflow((String) activityMap.get(WORKFLOW.getElementName()));
222 activities.add(activity);
224 return new ListDataDefinition<>();
227 return new ListDataDefinition<>();
231 return new ListDataDefinition<>();
237 private ListDataDefinition<OperationInputDefinition> handleInterfaceOperationInputs(final Map<String, Object> interfaceInputs) {
238 final ListDataDefinition<OperationInputDefinition> inputs = new ListDataDefinition<>();
239 for (final Entry<String, Object> interfaceInput : interfaceInputs.entrySet()) {
240 final OperationInputDefinition operationInput = new OperationInputDefinition();
241 operationInput.setUniqueId(UUID.randomUUID().toString());
242 operationInput.setInputId(operationInput.getUniqueId());
243 operationInput.setName(interfaceInput.getKey());
244 handleInputToscaDefinition(interfaceInput.getKey(), interfaceInput.getValue(), operationInput);
245 inputs.add(operationInput);
250 private void handleInputToscaDefinition(final String inputName, final Object value, final OperationInputDefinition operationInput) {
251 if (value instanceof Map) {
252 final LinkedHashMap<String, Object> inputPropertyValue = (LinkedHashMap<String, Object>) value;
253 LOGGER.debug("Creating interface operation input '{}'", inputName);
254 if (inputPropertyValue.get(TYPE.getElementName()) != null) {
255 final String type = inputPropertyValue.get(TYPE.getElementName()).toString();
256 LOGGER.debug(WITH_ATTRIBUTE, TYPE.getElementName(), type);
257 operationInput.setType(type);
259 if (inputPropertyValue.get(DESCRIPTION.getElementName()) != null) {
260 final String description = inputPropertyValue.get(DESCRIPTION.getElementName()).toString();
261 LOGGER.debug(WITH_ATTRIBUTE, DESCRIPTION.getElementName(), description);
262 operationInput.setDescription(description);
264 if (inputPropertyValue.get(REQUIRED.getElementName()) != null) {
265 final boolean required = Boolean.parseBoolean(inputPropertyValue.get(REQUIRED.getElementName()).toString());
266 LOGGER.debug(WITH_ATTRIBUTE, REQUIRED.getElementName(), required);
267 operationInput.setRequired(required);
269 if (inputPropertyValue.get(DEFAULT.getElementName()) != null) {
270 final Gson gson = new Gson();
271 final String json = gson.toJson(inputPropertyValue.get(DEFAULT.getElementName()));
272 LOGGER.debug(WITH_ATTRIBUTE, DEFAULT.getElementName(), json);
273 operationInput.setToscaDefaultValue(json);
275 if (inputPropertyValue.get(VALUE.getElementName()) != null) {
276 final Gson gson = new Gson();
277 final String json = gson.toJson(inputPropertyValue.get(VALUE.getElementName()));
278 operationInput.setValue(json);
280 if (inputPropertyValue.get(STATUS.getElementName()) != null) {
281 final String status = inputPropertyValue.get(STATUS.getElementName()).toString();
282 LOGGER.debug(WITH_ATTRIBUTE, STATUS.getElementName(), status);
283 operationInput.setStatus(status);
287 if (value instanceof String) {
288 final String stringValue = (String) value;
289 operationInput.setDefaultValue(stringValue);
290 operationInput.setToscaDefaultValue(stringValue);
291 operationInput.setValue(stringValue);
295 @SuppressWarnings("unchecked")
296 private Optional<ArtifactDataDefinition> handleOperationImplementation(final Map<String, Object> operationDefinitionMap) {
297 if (!operationDefinitionMap.containsKey(IMPLEMENTATION.getElementName())) {
298 return Optional.empty();
300 final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition();
301 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof Map &&
302 ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).containsKey("primary")) {
303 Map<String, Object> implDetails = (Map) ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).get("primary");
305 if (implDetails.get("file") != null) {
306 final String file = implDetails.get("file").toString();
307 artifactDataDefinition.setArtifactName(generateArtifactName(file));
309 if (implDetails.get("type") != null) {
310 artifactDataDefinition.setArtifactType(implDetails.get("type").toString());
312 if (implDetails.get("artifact_version") != null) {
313 artifactDataDefinition.setArtifactVersion(implDetails.get("artifact_version").toString());
316 if (implDetails.get("properties") instanceof Map) {
317 List<PropertyDataDefinition> operationProperties =
318 artifactDataDefinition.getProperties() == null ? new ArrayList<>() : artifactDataDefinition.getProperties();
319 Map<String, Object> properties = (Map<String, Object>) implDetails.get("properties");
320 properties.forEach((k, v) -> {
321 ToscaPropertyType type = getTypeFromObject(v);
323 PropertyDataDefinition propertyDef = new PropertyDataDefinition();
324 propertyDef.setName(k);
325 propertyDef.setType(type.getType());
326 propertyDef.setValue(v.toString());
327 if (type.equals(ToscaPropertyType.LIST)) {
328 Gson gson = new Gson();
329 propertyDef.setValue(gson.toJson(v));
330 PropertyDataDefinition pdd = new PropertyDataDefinition();
331 pdd.setType("string");
332 SchemaDefinition sd = new SchemaDefinition();
334 propertyDef.setSchema(sd);
336 artifactDataDefinition.addProperty(propertyDef);
342 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof Map &&
343 ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).containsKey("timeout")) {
344 final Object timeOut = ((Map) operationDefinitionMap.get(IMPLEMENTATION.getElementName())).get("timeout");
345 artifactDataDefinition.setTimeout((Integer)timeOut);
348 if (operationDefinitionMap.get(IMPLEMENTATION.getElementName()) instanceof String) {
349 final String implementation = (String) operationDefinitionMap.get(IMPLEMENTATION.getElementName());
350 artifactDataDefinition.setArtifactName(generateArtifactName(implementation));
352 return Optional.of(artifactDataDefinition);
355 private String generateArtifactName(final String name) {
356 if (OperationArtifactUtil.artifactNameIsALiteralValue(name)) {
359 return QUOTE + name + QUOTE;
363 private ToscaPropertyType getTypeFromObject(final Object value) {
364 if (value instanceof String) {
365 return ToscaPropertyType.STRING;
367 if (value instanceof Integer) {
368 return ToscaPropertyType.INTEGER;
370 if (value instanceof Boolean) {
371 return ToscaPropertyType.BOOLEAN;
373 if (value instanceof Float || value instanceof Double) {
374 return ToscaPropertyType.FLOAT;
376 if (value instanceof List) {
377 return ToscaPropertyType.LIST;
383 private Map<String, InputDefinition> handleInputs(final Map<String, Object> interfaceDefinitionToscaMap) {
384 if (!interfaceDefinitionToscaMap.containsKey(INPUTS.getElementName())) {
385 return Collections.emptyMap();
387 final Either<Map<String, InputDefinition>, ResultStatusEnum> inputMapEither = ImportUtils.getInputs(interfaceDefinitionToscaMap);
388 if (inputMapEither.isRight()) {
389 return Collections.emptyMap();
391 return inputMapEither.left().value();