Fix default value for interface operation input
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / InterfaceDefinitionHandler.java
1 /*
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
8  *
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.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19 package org.openecomp.sdc.be.components.impl;
20
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;
31
32 import com.google.gson.Gson;
33 import fj.data.Either;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.LinkedHashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Optional;
41 import java.util.UUID;
42 import java.util.stream.Collectors;
43 import org.apache.commons.collections.MapUtils;
44 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
45 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
46 import org.openecomp.sdc.be.dao.api.ActionStatus;
47 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
48 import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition;
49 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
50 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
51 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
52 import org.openecomp.sdc.be.model.InputDefinition;
53 import org.openecomp.sdc.be.model.InterfaceDefinition;
54 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
55 import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
56 import org.openecomp.sdc.exception.ResponseFormat;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.springframework.stereotype.Component;
60
61 /**
62  * Handles interface definition TOSCA conversions
63  */
64 @Component("interfaceDefinitionHandler")
65 public class InterfaceDefinitionHandler {
66
67     private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceDefinitionHandler.class);
68     private static final String WITH_ATTRIBUTE = "with attribute '{}': '{}'";
69     private final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic;
70
71     public InterfaceDefinitionHandler(final InterfaceOperationBusinessLogic interfaceOperationBusinessLogic) {
72         this.interfaceOperationBusinessLogic = interfaceOperationBusinessLogic;
73     }
74
75     /**
76      * Creates an interface definition based on a TOSCA map representing an interface definition.
77      *
78      * @param interfaceDefinitionToscaMap the TOSCA interface definition structure
79      * @return an interface definition representation
80      */
81     public InterfaceDefinition create(final Map<String, Object> interfaceDefinitionToscaMap, final String model) {
82         final InterfaceDefinition interfaceDefinition = new InterfaceDefinition();
83         interfaceDefinition.setModel(model);
84         if (interfaceDefinitionToscaMap.containsKey(TYPE.getElementName())) {
85             final Object typeObj = interfaceDefinitionToscaMap.get(TYPE.getElementName());
86             if (!(typeObj instanceof String)) {
87                 throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML);
88             }
89             final String type = (String) typeObj;
90             interfaceDefinition.setType(type);
91             interfaceDefinition.setUniqueId(type.toLowerCase());
92         }
93         final Map<String, InputDefinition> inputDefinitionMap = handleInputs(interfaceDefinitionToscaMap);
94         if (!inputDefinitionMap.isEmpty()) {
95             final Map<String, InputDataDefinition> collect = inputDefinitionMap.entrySet().stream()
96                 .collect(Collectors.toMap(Entry::getKey, value -> new InputDataDefinition(value.getValue())));
97             interfaceDefinition.setInputs(collect);
98         }
99         final Map<String, OperationDataDefinition> operationMap;
100         if (interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName()) || interfaceDefinitionToscaMap
101             .containsKey(NOTIFICATIONS.getElementName())) {
102             operationMap = handleOperations(interfaceDefinitionToscaMap);
103             //TODO handle notifications
104         } else {
105             operationMap = handleLegacyOperations(interfaceDefinitionToscaMap);
106         }
107         if (!operationMap.isEmpty()) {
108             validateOperations(interfaceDefinition.getType(), operationMap, model);
109             interfaceDefinition.setOperations(operationMap);
110         }
111         return interfaceDefinition;
112     }
113
114     private void validateOperations(final String interfaceType, final Map<String, OperationDataDefinition> operationMap, final String model) {
115         if (MapUtils.isEmpty(operationMap)) {
116             return;
117         }
118         Either<Map<String, InterfaceDefinition>, ResponseFormat> interfaceDefinitionMapEither = interfaceOperationBusinessLogic
119             .getAllInterfaceLifecycleTypes(model);
120         if (interfaceDefinitionMapEither.isRight() || MapUtils.isEmpty(interfaceDefinitionMapEither.left().value())) {
121             throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
122         }
123         final Map<String, InterfaceDefinition> interfaceDefinitionMap = interfaceDefinitionMapEither.left().value();
124         final Optional<InterfaceDefinition> interfaceDefinitionOptional = interfaceDefinitionMap.entrySet().stream()
125             .filter(interfaceDefinitionEntry -> interfaceDefinitionEntry.getKey().equalsIgnoreCase(UniqueIdBuilder.buildInterfaceTypeUid(model, interfaceType))).map(Entry::getValue).findFirst();
126         if (interfaceDefinitionOptional.isEmpty()) {
127             throw new ByActionStatusComponentException(ActionStatus.INTERFACE_UNKNOWN, interfaceType);
128         }
129         final InterfaceDefinition interfaceDefinition = interfaceDefinitionOptional.get();
130         operationMap.keySet().forEach(operation1 -> {
131             if (!interfaceDefinition.hasOperation(operation1)) {
132                 throw new ByActionStatusComponentException(ActionStatus.INTERFACE_OPERATION_NOT_DEFINED, operation1, interfaceType);
133             }
134         });
135     }
136
137     private Map<String, OperationDataDefinition> handleOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
138         if (!interfaceDefinitionToscaMap.containsKey(OPERATIONS.getElementName())) {
139             return Collections.emptyMap();
140         }
141         final Map<String, Object> operationMap = (Map<String, Object>) interfaceDefinitionToscaMap.get(OPERATIONS.getElementName());
142         return operationMap.entrySet().stream()
143             .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
144             .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
145     }
146
147     private Map<String, OperationDataDefinition> handleLegacyOperations(final Map<String, Object> interfaceDefinitionToscaMap) {
148         final List<String> notALegacyOperationEntry = Arrays
149             .asList(OPERATIONS.getElementName(), TYPE.getElementName(), INPUTS.getElementName(), NOTIFICATIONS.getElementName());
150         return interfaceDefinitionToscaMap.entrySet().stream().filter(interfaceEntry -> !notALegacyOperationEntry.contains(interfaceEntry.getKey()))
151             .map(interfaceEntry -> createOperation(interfaceEntry.getKey(), (Map<String, Object>) interfaceEntry.getValue()))
152             .collect(Collectors.toMap(OperationDataDefinition::getName, operationDataDefinition -> operationDataDefinition));
153     }
154
155     private OperationDataDefinition createOperation(final String operationName, final Map<String, Object> operationDefinitionMap) {
156         final OperationDataDefinition operation = new OperationDataDefinition();
157         operation.setUniqueId(UUID.randomUUID().toString());
158         operation.setName(operationName);
159         operation.setImplementation(handleOperationImplementation(operationDefinitionMap).orElse(new ArtifactDataDefinition()));
160         if (operationDefinitionMap.containsKey(INPUTS.getElementName())) {
161             final Map<String, Object> interfaceInputs = (Map<String, Object>) operationDefinitionMap.get(INPUTS.getElementName());
162             operation.setInputs(handleInterfaceOperationInputs(interfaceInputs));
163         }
164         return operation;
165     }
166
167     private ListDataDefinition<OperationInputDefinition> handleInterfaceOperationInputs(final Map<String, Object> interfaceInputs) {
168         final ListDataDefinition<OperationInputDefinition> inputs = new ListDataDefinition<>();
169         for (final Entry<String, Object> interfaceInput : interfaceInputs.entrySet()) {
170             final OperationInputDefinition operationInput = new OperationInputDefinition();
171             operationInput.setUniqueId(UUID.randomUUID().toString());
172             operationInput.setInputId(operationInput.getUniqueId());
173             operationInput.setName(interfaceInput.getKey());
174             handleInputToscaDefinition(interfaceInput.getKey(), interfaceInput.getValue(), operationInput);
175             inputs.add(operationInput);
176         }
177         return inputs;
178     }
179
180     private void handleInputToscaDefinition(final String inputName, final Object value, final OperationInputDefinition operationInput) {
181         if (value instanceof Map) {
182             final LinkedHashMap<String, Object> inputPropertyValue = (LinkedHashMap<String, Object>) value;
183             LOGGER.debug("Creating interface operation input '{}'", inputName);
184             if (inputPropertyValue.get(TYPE.getElementName()) != null) {
185                 final String type = inputPropertyValue.get(TYPE.getElementName()).toString();
186                 LOGGER.debug(WITH_ATTRIBUTE, TYPE.getElementName(), type);
187                 operationInput.setType(type);
188             }
189             if (inputPropertyValue.get(DESCRIPTION.getElementName()) != null) {
190                 final String description = inputPropertyValue.get(DESCRIPTION.getElementName()).toString();
191                 LOGGER.debug(WITH_ATTRIBUTE, DESCRIPTION.getElementName(), description);
192                 operationInput.setDescription(description);
193             }
194             if (inputPropertyValue.get(REQUIRED.getElementName()) != null) {
195                 final boolean required = Boolean.parseBoolean(inputPropertyValue.get(REQUIRED.getElementName()).toString());
196                 LOGGER.debug(WITH_ATTRIBUTE, REQUIRED.getElementName(), required);
197                 operationInput.setRequired(required);
198             }
199             if (inputPropertyValue.get(DEFAULT.getElementName()) != null) {
200                 final Gson gson = new Gson();
201                 final String json = gson.toJson(inputPropertyValue.get(DEFAULT.getElementName()));
202                 LOGGER.debug(WITH_ATTRIBUTE, DEFAULT.getElementName(), json);
203                 operationInput.setToscaDefaultValue(json);
204             }
205             if (inputPropertyValue.get(STATUS.getElementName()) != null) {
206                 final String status = inputPropertyValue.get(STATUS.getElementName()).toString();
207                 LOGGER.debug(WITH_ATTRIBUTE, STATUS.getElementName(), status);
208                 operationInput.setStatus(status);
209             }
210             return;
211         }
212         if (value instanceof String) {
213             final String stringValue = (String) value;
214             operationInput.setDefaultValue(stringValue);
215             operationInput.setToscaDefaultValue(stringValue);
216             operationInput.setValue(stringValue);
217         }
218     }
219
220     private Optional<ArtifactDataDefinition> handleOperationImplementation(final Map<String, Object> operationDefinitionMap) {
221         if (!operationDefinitionMap.containsKey(IMPLEMENTATION.getElementName())) {
222             return Optional.empty();
223         }
224         final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition();
225         final String artifactName = (String) operationDefinitionMap.get(IMPLEMENTATION.getElementName());
226         if (OperationArtifactUtil.artifactNameIsALiteralValue(artifactName)) {
227             artifactDataDefinition.setArtifactName(artifactName);
228         } else {
229             artifactDataDefinition.setArtifactName(QUOTE + artifactName + QUOTE);
230         }
231         return Optional.of(artifactDataDefinition);
232     }
233
234     private Map<String, InputDefinition> handleInputs(final Map<String, Object> interfaceDefinitionToscaMap) {
235         if (!interfaceDefinitionToscaMap.containsKey(INPUTS.getElementName())) {
236             return Collections.emptyMap();
237         }
238         final Either<Map<String, InputDefinition>, ResultStatusEnum> inputMapEither = ImportUtils.getInputs(interfaceDefinitionToscaMap);
239         if (inputMapEither.isRight()) {
240             return Collections.emptyMap();
241         }
242         return inputMapEither.left().value();
243     }
244 }