Fix NPE when deleting interface operation
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / impl / InterfaceOperationBusinessLogic.java
1 /*
2  * Copyright © 2016-2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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 package org.openecomp.sdc.be.components.impl;
17
18 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.createMappedCapabilityPropertyDefaultValue;
19 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.createMappedInputPropertyDefaultValue;
20 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.createMappedOutputDefaultValue;
21 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getInterfaceDefinitionFromComponentByInterfaceId;
22 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getInterfaceDefinitionFromComponentByInterfaceType;
23 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationFromInterfaceDefinition;
24 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToComponentInput;
25 import static org.openecomp.sdc.be.components.utils.PropertiesUtils.getPropertyCapabilityFromAllCapProps;
26 import static org.openecomp.sdc.be.components.utils.PropertiesUtils.isCapabilityProperty;
27 import static org.openecomp.sdc.be.tosca.InterfacesOperationsConverter.SELF;
28
29 import com.google.gson.Gson;
30 import fj.data.Either;
31 import java.util.ArrayList;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Map.Entry;
38 import java.util.Objects;
39 import java.util.Optional;
40 import java.util.UUID;
41 import java.util.stream.Collectors;
42 import org.apache.commons.collections4.CollectionUtils;
43 import org.apache.commons.collections4.MapUtils;
44 import org.apache.commons.lang3.StringUtils;
45 import org.apache.commons.lang3.tuple.ImmutablePair;
46 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
47 import org.openecomp.sdc.be.components.utils.InterfaceOperationUtils;
48 import org.openecomp.sdc.be.components.validation.InterfaceOperationValidation;
49 import org.openecomp.sdc.be.dao.api.ActionStatus;
50 import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao;
51 import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus;
52 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
53 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
54 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
55 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
56 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
57 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
58 import org.openecomp.sdc.be.model.ArtifactDefinition;
59 import org.openecomp.sdc.be.model.CapabilityDefinition;
60 import org.openecomp.sdc.be.model.Component;
61 import org.openecomp.sdc.be.model.ComponentInstanceInterface;
62 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
63 import org.openecomp.sdc.be.model.InputDefinition;
64 import org.openecomp.sdc.be.model.InterfaceDefinition;
65 import org.openecomp.sdc.be.model.Operation;
66 import org.openecomp.sdc.be.model.User;
67 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
68 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
69 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
70 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
71 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
72 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
73 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
74 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
75 import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum;
76 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
77 import org.openecomp.sdc.exception.ResponseFormat;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80 import org.springframework.beans.factory.annotation.Autowired;
81
82 @org.springframework.stereotype.Component("interfaceOperationBusinessLogic")
83 public class InterfaceOperationBusinessLogic extends BaseBusinessLogic {
84
85     private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationBusinessLogic.class);
86     private static final String EXCEPTION_OCCURRED_DURING_INTERFACE_OPERATION = "Exception occurred during {}. Response is {}";
87     private static final String DELETE_INTERFACE_OPERATION = "deleteInterfaceOperation";
88     private static final String GET_INTERFACE_OPERATION = "getInterfaceOperation";
89     private static final String CREATE_INTERFACE_OPERATION = "createInterfaceOperation";
90     private static final String UPDATE_INTERFACE_OPERATION = "updateInterfaceOperation";
91     private final ArtifactCassandraDao artifactCassandraDao;
92     private final InterfaceOperationValidation interfaceOperationValidation;
93
94     @Autowired
95     public InterfaceOperationBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation,
96                                            IGroupInstanceOperation groupInstanceOperation, IGroupTypeOperation groupTypeOperation,
97                                            InterfaceOperation interfaceOperation, InterfaceLifecycleOperation interfaceLifecycleTypeOperation,
98                                            ArtifactCassandraDao artifactCassandraDao, InterfaceOperationValidation interfaceOperationValidation,
99                                            ArtifactsOperations artifactToscaOperation) {
100         super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
101             artifactToscaOperation);
102         this.artifactCassandraDao = artifactCassandraDao;
103         this.interfaceOperationValidation = interfaceOperationValidation;
104     }
105
106     public Either<List<InterfaceDefinition>, ResponseFormat> deleteInterfaceOperation(String componentId, String interfaceId,
107                                                                                       List<String> operationsToDelete, User user, boolean lock) {
108         validateUserExists(user.getUserId());
109         Either<Component, ResponseFormat> componentEither = getComponentDetails(componentId);
110         if (componentEither.isRight()) {
111             return Either.right(componentEither.right().value());
112         }
113         Component storedComponent = componentEither.left().value();
114         lockComponentResult(lock, storedComponent, DELETE_INTERFACE_OPERATION);
115         try {
116             Optional<InterfaceDefinition> optionalInterface = getInterfaceDefinitionFromComponentByInterfaceId(storedComponent, interfaceId);
117             if (optionalInterface.isEmpty()) {
118                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT, interfaceId));
119             }
120             InterfaceDefinition interfaceDefinition = optionalInterface.get();
121             Map<String, Operation> operationsCollection = new HashMap<>();
122             for (String operationId : operationsToDelete) {
123                 Optional<Map.Entry<String, Operation>> optionalOperation = getOperationFromInterfaceDefinition(interfaceDefinition, operationId);
124                 if (optionalOperation.isEmpty()) {
125                     return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, storedComponent.getUniqueId()));
126                 }
127                 Operation storedOperation = optionalOperation.get().getValue();
128                 Either<Boolean, ResponseFormat> validateDeleteOperationContainsNoMappedOutputResponse = interfaceOperationValidation
129                     .validateDeleteOperationContainsNoMappedOutput(storedOperation, storedComponent, interfaceDefinition);
130                 if (validateDeleteOperationContainsNoMappedOutputResponse.isRight()) {
131                     return Either.right(validateDeleteOperationContainsNoMappedOutputResponse.right().value());
132                 }
133                 final ArtifactDataDefinition implementation = storedOperation.getImplementation();
134                 if (implementation != null && implementation.getUniqueId() != null && !InterfaceOperationUtils.isArtifactInUse(storedComponent, operationId, implementation.getUniqueId())) {
135                     final String artifactUniqueId = implementation.getUniqueId();
136                     Either<ArtifactDefinition, StorageOperationStatus> getArtifactEither = artifactToscaOperation
137                         .getArtifactById(storedComponent.getUniqueId(), artifactUniqueId);
138                     if (getArtifactEither.isLeft()) {
139                         Either<ArtifactDefinition, StorageOperationStatus> removeArifactFromComponent = artifactToscaOperation
140                             .removeArifactFromResource(componentId, artifactUniqueId,
141                                 NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue()), true);
142                         if (removeArifactFromComponent.isRight()) {
143                             janusGraphDao.rollback();
144                             ResponseFormat responseFormatByArtifactId = componentsUtils
145                                 .getResponseFormatByArtifactId(componentsUtils.convertFromStorageResponse(removeArifactFromComponent.right().value()),
146                                         implementation.getArtifactDisplayName());
147                             return Either.right(responseFormatByArtifactId);
148                         }
149                         CassandraOperationStatus cassandraStatus = artifactCassandraDao.deleteArtifact(artifactUniqueId);
150                         if (cassandraStatus != CassandraOperationStatus.OK) {
151                             janusGraphDao.rollback();
152                             ResponseFormat responseFormatByArtifactId = componentsUtils.getResponseFormatByArtifactId(
153                                 componentsUtils.convertFromStorageResponse(componentsUtils.convertToStorageOperationStatus(cassandraStatus)),
154                                 implementation.getArtifactDisplayName());
155                             return Either.right(responseFormatByArtifactId);
156                         }
157                     }
158                 }
159                 operationsCollection.put(operationId, interfaceDefinition.getOperationsMap().get(operationId));
160                 final Optional<String> operationKeyOptional = interfaceDefinition.getOperations().entrySet()
161                     .stream().filter(entry -> operationId.equals(entry.getValue().getUniqueId()))
162                     .map(Entry::getKey).findFirst();
163                 if (operationKeyOptional.isEmpty()) {
164                     return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, storedComponent.getUniqueId()));
165                 }
166                 interfaceDefinition.getOperations().remove(operationKeyOptional.get());
167             }
168             final Either<List<InterfaceDefinition>, StorageOperationStatus> updateInterfaceResultEither;
169             updateInterfaceResultEither = interfaceOperation.updateInterfaces(storedComponent, Collections.singletonList(interfaceDefinition));
170             if (updateInterfaceResultEither.isRight()) {
171                 janusGraphDao.rollback();
172                 return Either.right(componentsUtils.getResponseFormat(
173                     componentsUtils.convertFromStorageResponse(updateInterfaceResultEither.right().value(), storedComponent.getComponentType())));
174             }
175             if (interfaceDefinition.getOperations().isEmpty()) {
176                 final var deleteInterfaceEither = interfaceOperation.deleteInterface(storedComponent, interfaceDefinition.getUniqueId());
177                 if (deleteInterfaceEither.isRight()) {
178                     janusGraphDao.rollback();
179                     return Either.right(componentsUtils.getResponseFormat(
180                         componentsUtils.convertFromStorageResponse(deleteInterfaceEither.right().value(), storedComponent.getComponentType())));
181                 }
182             }
183             janusGraphDao.commit();
184             interfaceDefinition.getOperations().putAll(operationsCollection);
185             interfaceDefinition.getOperations().keySet().removeIf(key -> !(operationsToDelete.contains(key)));
186             return Either.left(Collections.singletonList(interfaceDefinition));
187         } catch (Exception e) {
188             LOGGER.error(EXCEPTION_OCCURRED_DURING_INTERFACE_OPERATION, "delete", e);
189             janusGraphDao.rollback();
190             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_DELETED));
191         } finally {
192             graphLockOperation
193                 .unlockComponent(storedComponent.getUniqueId(), NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue()));
194         }
195     }
196
197     private Either<Component, ResponseFormat> getComponentDetails(String componentId) {
198         Either<Component, StorageOperationStatus> componentStorageOperationStatusEither = toscaOperationFacade
199             .getToscaElement(componentId);
200         if (componentStorageOperationStatusEither.isRight()) {
201             return Either.right(
202                 componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(componentStorageOperationStatusEither.right().value())));
203         }
204         return Either.left(componentStorageOperationStatusEither.left().value());
205     }
206
207     private Either<Boolean, ResponseFormat> lockComponentResult(boolean lock, Component component, String action) {
208         if (lock) {
209             try {
210                 lockComponent(component.getUniqueId(), component, action);
211             } catch (ComponentException e) {
212                 janusGraphDao.rollback();
213                 throw e;
214             }
215         }
216         return Either.left(true);
217     }
218
219     public Either<List<InterfaceDefinition>, ResponseFormat> getInterfaceOperation(String componentId, String interfaceId,
220                                                                                    List<String> operationsToGet, User user, boolean lock) {
221         validateUserExists(user);
222         Either<Component, ResponseFormat> componentEither = getComponentDetails(componentId);
223         if (componentEither.isRight()) {
224             return Either.right(componentEither.right().value());
225         }
226         Component storedComponent = componentEither.left().value();
227         lockComponentResult(lock, storedComponent, GET_INTERFACE_OPERATION);
228         try {
229             Optional<InterfaceDefinition> optionalInterface = getInterfaceDefinitionFromComponentByInterfaceId(storedComponent, interfaceId);
230             if (!optionalInterface.isPresent()) {
231                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_NOT_FOUND_IN_COMPONENT, interfaceId));
232             }
233             InterfaceDefinition interfaceDefinition = optionalInterface.get();
234             for (String operationId : operationsToGet) {
235                 Optional<Map.Entry<String, Operation>> optionalOperation = getOperationFromInterfaceDefinition(interfaceDefinition, operationId);
236                 if (!optionalOperation.isPresent()) {
237                     return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, storedComponent.getUniqueId()));
238                 }
239             }
240             janusGraphDao.commit();
241             interfaceDefinition.getOperations().keySet().removeIf(key -> !(operationsToGet.contains(key)));
242             return Either.left(Collections.singletonList(interfaceDefinition));
243         } catch (Exception e) {
244             LOGGER.error(EXCEPTION_OCCURRED_DURING_INTERFACE_OPERATION, "get", e);
245             janusGraphDao.rollback();
246             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, componentId));
247         } finally {
248             graphLockOperation
249                 .unlockComponent(storedComponent.getUniqueId(), NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue()));
250         }
251     }
252
253     public Either<List<InterfaceDefinition>, ResponseFormat> createInterfaceOperation(String componentId,
254                                                                                       List<InterfaceDefinition> interfaceDefinitions, User user,
255                                                                                       boolean lock) {
256         return createOrUpdateInterfaceOperation(componentId, interfaceDefinitions, user, false, CREATE_INTERFACE_OPERATION, lock);
257     }
258
259     private Either<List<InterfaceDefinition>, ResponseFormat> createOrUpdateInterfaceOperation(String componentId,
260                                                                                                List<InterfaceDefinition> interfaceDefinitions,
261                                                                                                User user, boolean isUpdate, String errorContext,
262                                                                                                boolean lock) {
263         validateUserExists(user);
264         Either<Component, ResponseFormat> componentEither = getComponentDetails(componentId);
265         if (componentEither.isRight()) {
266             return Either.right(componentEither.right().value());
267         }
268         Component storedComponent = componentEither.left().value();
269         lockComponentResult(lock, storedComponent, errorContext);
270         Either<Map<String, InterfaceDefinition>, ResponseFormat> interfaceLifecycleTypes = getAllInterfaceLifecycleTypes(storedComponent.getModel());
271         if (interfaceLifecycleTypes.isRight()) {
272             return Either.right(interfaceLifecycleTypes.right().value());
273         }
274         try {
275             List<InterfaceDefinition> interfacesCollection = new ArrayList<>();
276             Map<String, Operation> operationsCollection = new HashMap<>();
277             for (InterfaceDefinition inputInterfaceDefinition : interfaceDefinitions) {
278                 Optional<InterfaceDefinition> optionalInterface = getInterfaceDefinitionFromComponentByInterfaceType(storedComponent,
279                     inputInterfaceDefinition.getType());
280                 Either<Boolean, ResponseFormat> interfaceOperationValidationResponseEither = interfaceOperationValidation
281                     .validateInterfaceOperations(inputInterfaceDefinition, storedComponent, optionalInterface.orElse(null),
282                         interfaceLifecycleTypes.left().value(), isUpdate);
283                 if (interfaceOperationValidationResponseEither.isRight()) {
284                     return Either.right(interfaceOperationValidationResponseEither.right().value());
285                 }
286                 Map<String, Operation> operationsToAddOrUpdate = inputInterfaceDefinition.getOperationsMap();
287                 operationsCollection.putAll(operationsToAddOrUpdate);
288                 inputInterfaceDefinition.getOperations().clear();
289                 Either<InterfaceDefinition, ResponseFormat> getInterfaceEither = getOrCreateInterfaceDefinition(storedComponent,
290                     inputInterfaceDefinition, optionalInterface.orElse(null));
291                 if (getInterfaceEither.isRight()) {
292                     return Either.right(getInterfaceEither.right().value());
293                 }
294                 InterfaceDefinition interfaceDef = getInterfaceEither.left().value();
295                 updateOperationInputDefs(storedComponent, operationsToAddOrUpdate.values());
296                 for (Operation operation : operationsToAddOrUpdate.values()) {
297                     if (!isUpdate) {
298                         addOperationToInterface(interfaceDef, operation);
299                     } else {
300                         Optional<Map.Entry<String, Operation>> optionalOperation = getOperationFromInterfaceDefinition(interfaceDef,
301                             operation.getUniqueId());
302                         if (optionalOperation.isEmpty()) {
303                             janusGraphDao.rollback();
304                             return Either
305                                 .right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, storedComponent.getUniqueId()));
306                         }
307                         final Operation storedOperation = optionalOperation.get().getValue();
308                         final ArtifactDataDefinition implementation = storedOperation.getImplementation();
309                         final String artifactUniqueId = implementation.getUniqueId();
310                         if (StringUtils.isNotEmpty(artifactUniqueId)) {
311                             if (!InterfaceOperationUtils.isArtifactInUse(storedComponent, storedOperation.getUniqueId(), artifactUniqueId)) {
312                                 Either<ArtifactDefinition, StorageOperationStatus> getArtifactEither = artifactToscaOperation
313                                     .getArtifactById(storedComponent.getUniqueId(), artifactUniqueId);
314                                 if (getArtifactEither.isLeft()) {
315                                     Either<ArtifactDefinition, StorageOperationStatus> removeArifactFromComponent = artifactToscaOperation
316                                         .removeArifactFromResource(componentId, artifactUniqueId,
317                                             NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue()), true);
318                                     if (removeArifactFromComponent.isRight()) {
319                                         janusGraphDao.rollback();
320                                         ResponseFormat responseFormatByArtifactId = componentsUtils.getResponseFormatByArtifactId(
321                                             componentsUtils.convertFromStorageResponse(removeArifactFromComponent.right().value()),
322                                             implementation.getArtifactDisplayName());
323                                         return Either.right(responseFormatByArtifactId);
324                                     }
325                                     CassandraOperationStatus cassandraStatus = artifactCassandraDao.deleteArtifact(artifactUniqueId);
326                                     if (cassandraStatus != CassandraOperationStatus.OK) {
327                                         janusGraphDao.rollback();
328                                         ResponseFormat responseFormatByArtifactId = componentsUtils.getResponseFormatByArtifactId(
329                                             componentsUtils.convertFromStorageResponse(
330                                                 componentsUtils.convertToStorageOperationStatus(cassandraStatus)),
331                                             implementation.getArtifactDisplayName());
332                                         return Either.right(responseFormatByArtifactId);
333                                     }
334                                 }
335                             }
336                         }
337                         updateOperationOnInterface(interfaceDef, operation, implementation.getArtifactUUID());
338                     }
339                 }
340                 interfacesCollection.add(interfaceDef);
341             }
342             final var addCreateOperationEither = interfaceOperation.updateInterfaces(storedComponent, interfacesCollection);
343             if (addCreateOperationEither.isRight()) {
344                 janusGraphDao.rollback();
345                 return Either.right(componentsUtils.getResponseFormat(
346                     componentsUtils.convertFromStorageResponse(addCreateOperationEither.right().value(), storedComponent.getComponentType())));
347             }
348             janusGraphDao.commit();
349             interfacesCollection.forEach(interfaceDefinition -> interfaceDefinition.getOperations().entrySet().removeIf(
350                 entry -> !operationsCollection.values().stream().map(OperationDataDefinition::getName).collect(Collectors.toList())
351                     .contains(entry.getValue().getName())));
352             return Either.left(interfacesCollection);
353         } catch (Exception e) {
354             janusGraphDao.rollback();
355             LOGGER.error(EXCEPTION_OCCURRED_DURING_INTERFACE_OPERATION, "addOrUpdate", e);
356             return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
357         } finally {
358             graphLockOperation
359                 .unlockComponent(storedComponent.getUniqueId(), NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue()));
360         }
361     }
362
363     public Either<Map<String, InterfaceDefinition>, ResponseFormat> getAllInterfaceLifecycleTypes(final String model) {
364         Either<Map<String, InterfaceDefinition>, StorageOperationStatus> interfaceLifecycleTypes = interfaceLifecycleTypeOperation
365             .getAllInterfaceLifecycleTypes(model);
366         if (interfaceLifecycleTypes.isRight()) {
367             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_LIFECYCLE_TYPES_NOT_FOUND));
368         }
369         interfaceLifecycleTypes.left().value().values().forEach(id -> id.setOperations(id.getOperations().keySet().stream()
370             .collect(Collectors.toMap(key -> key.replaceFirst(id.getUniqueId() + ".", ""), i -> id.getOperations().get(i)))));
371         return Either.left(interfaceLifecycleTypes.left().value());
372     }
373
374     private Either<InterfaceDefinition, ResponseFormat> getOrCreateInterfaceDefinition(Component component,
375                                                                                        InterfaceDefinition interfaceDefinition,
376                                                                                        InterfaceDefinition storedInterfaceDef) {
377         if (storedInterfaceDef != null) {
378             return Either.left(storedInterfaceDef);
379         }
380         interfaceDefinition.setUniqueId(UUID.randomUUID().toString());
381         interfaceDefinition.setToscaResourceName(interfaceDefinition.getType());
382         final var interfaceCreateEither = interfaceOperation.addInterfaces(component, Collections.singletonList(interfaceDefinition));
383         if (interfaceCreateEither.isRight()) {
384             janusGraphDao.rollback();
385             return Either.right(componentsUtils
386                 .getResponseFormat(componentsUtils.convertFromStorageResponse(interfaceCreateEither.right().value(), component.getComponentType())));
387         }
388         return Either.left(interfaceCreateEither.left().value().get(0));
389     }
390
391     private void updateOperationInputDefs(Component component, Collection<Operation> interfaceOperations) {
392         interfaceOperations.stream().filter(operation -> Objects.nonNull(operation.getInputs())).forEach(
393             operation -> operation.getInputs().getListToscaDataDefinition()
394                 .forEach(inp -> component.getInputs().forEach(in -> updateOperationInputDefinition(component, inp, in))));
395     }
396
397     private void updateOperationInputDefinition(Component component, OperationInputDefinition operationInput,
398                                                 InputDefinition componentInput) {
399         if (operationInput.getInputId().equals(componentInput.getUniqueId())) {
400             //Set the default value, value and schema only for inputs mapped to component inputs
401             operationInput.setDefaultValue(componentInput.getDefaultValue());
402             operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component));
403             operationInput.setValue(componentInput.getValue());
404             operationInput.setSchema(componentInput.getSchema());
405             operationInput.setParentPropertyType(componentInput.getParentPropertyType());
406             operationInput.setSubPropertyInputPath(componentInput.getSubPropertyInputPath());
407         }
408         //Set the tosca default value for inputs mapped to component inputs as well as other outputs
409         operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component));
410     }
411
412     private String getInputToscaDefaultValue(OperationInputDefinition input, Component component) {
413         Map<String, List<String>> defaultInputValue = null;
414         if (isOperationInputMappedToComponentInput(input, component.getInputs())) {
415             String propertyName = input.getInputId().substring(input.getInputId().indexOf('.') + 1);
416             setParentPropertyTypeAndInputPath(input, component);
417             defaultInputValue = createMappedInputPropertyDefaultValue(propertyName);
418         } else if (isCapabilityProperty(input.getInputId(), component).isPresent()) {
419             Optional<ComponentInstanceProperty> instancePropertyOpt = isCapabilityProperty(input.getInputId(), component);
420             Optional<String> parentPropertyIdOpt = instancePropertyOpt.map(PropertyDataDefinition::getParentUniqueId);
421             Map<String, List<CapabilityDefinition>> componentCapabilities = component.getCapabilities();
422             if (MapUtils.isNotEmpty(componentCapabilities)) {
423                 List<CapabilityDefinition> capabilityDefinitionList = componentCapabilities.values().stream().flatMap(Collection::stream)
424                     .filter(capabilityDefinition -> capabilityDefinition.getOwnerId().equals(component.getUniqueId())).collect(Collectors.toList());
425                 defaultInputValue = parentPropertyIdOpt
426                     .flatMap(parentPropertyId -> getPropertyCapabilityFromAllCapProps(parentPropertyId, capabilityDefinitionList)).flatMap(
427                         capability -> instancePropertyOpt
428                             .map(instanceProperty -> new ImmutablePair<>(capability.getName(), instanceProperty.getName()))).map(tuple -> {
429                         String propertyName = tuple.right;
430                         String capabilityName = tuple.left;
431                         return createMappedCapabilityPropertyDefaultValue(capabilityName, propertyName);
432                     }).orElse(null);
433             }
434         } else {
435             //Currently inputs can only be mapped to a declared input or an other operation outputs
436             defaultInputValue = createMappedOutputDefaultValue(SELF, input.getInputId());
437         }
438         return new Gson().toJson(defaultInputValue);
439     }
440
441     private void setParentPropertyTypeAndInputPath(OperationInputDefinition input, Component component) {
442         if (CollectionUtils.isEmpty(component.getInputs())) {
443             return;
444         }
445         component.getInputs().stream().filter(inp -> inp.getUniqueId().equals(input.getInputId().substring(0, input.getInputId().lastIndexOf('.'))))
446             .forEach(inp -> {
447                 input.setParentPropertyType(inp.getParentPropertyType());
448                 if (Objects.nonNull(input.getName())) {
449                     input.setSubPropertyInputPath(input.getName().replaceAll("\\.", "#"));
450                 }
451             });
452     }
453
454     private void addOperationToInterface(InterfaceDefinition interfaceDefinition, Operation interfaceOperation) {
455         interfaceOperation.setUniqueId(UUID.randomUUID().toString());
456         interfaceOperation.setImplementation(createArtifactDefinition(UUID.randomUUID().toString(), interfaceOperation));
457         interfaceDefinition.getOperations().put(interfaceOperation.getUniqueId(), new OperationDataDefinition(interfaceOperation));
458     }
459
460     private void updateOperationOnInterface(InterfaceDefinition interfaceDefinition, Operation interfaceOperation, String artifactUuId) {
461         interfaceOperation.setImplementation(createArtifactDefinition(artifactUuId, interfaceOperation));
462         interfaceDefinition.getOperations().put(interfaceOperation.getUniqueId(), new OperationDataDefinition(interfaceOperation));
463     }
464
465     private ArtifactDefinition createArtifactDefinition(String artifactUuId, Operation operation) {
466         ArtifactDefinition artifactDefinition = new ArtifactDefinition();
467         artifactDefinition.setArtifactUUID(artifactUuId);
468         artifactDefinition.setUniqueId(artifactUuId);
469         artifactDefinition.setEsId(artifactUuId);
470         artifactDefinition.setArtifactType(ArtifactTypeEnum.WORKFLOW.getType());
471         artifactDefinition.setArtifactGroupType(ArtifactGroupTypeEnum.DEPLOYMENT);
472         artifactDefinition.setArtifactLabel(operation.getName() + ".workflowArtifact");
473         artifactDefinition.setArtifactName(operation.getWorkflowName() + "_" + operation.getWorkflowVersion());
474         return artifactDefinition;
475     }
476
477     public Either<List<InterfaceDefinition>, ResponseFormat> updateInterfaceOperation(String componentId,
478                                                                                       List<InterfaceDefinition> interfaceDefinitions, User user,
479                                                                                       boolean lock) {
480         return createOrUpdateInterfaceOperation(componentId, interfaceDefinitions, user, true, UPDATE_INTERFACE_OPERATION, lock);
481     }
482
483     public Either<List<OperationInputDefinition>, ResponseFormat> getInputsListForOperation(String componentId, String componentInstanceId,
484                                                                                             String interfaceId, String operationId, User user) {
485         Either<Component, ResponseFormat> componentEither = getComponentDetails(componentId);
486         if (componentEither.isRight()) {
487             return Either.right(componentEither.right().value());
488         }
489         Component storedComponent = componentEither.left().value();
490         validateUserExists(user.getUserId());
491         Either<Boolean, ResponseFormat> lockResult = lockComponentResult(true, storedComponent, GET_INTERFACE_OPERATION);
492         if (lockResult.isRight()) {
493             return Either.right(lockResult.right().value());
494         }
495         try {
496             Component parentComponent = componentEither.left().value();
497             Map<String, List<ComponentInstanceInterface>> componentInstanceInterfaces = parentComponent.getComponentInstancesInterfaces();
498             if (MapUtils.isEmpty(componentInstanceInterfaces)) {
499                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, componentInstanceId));
500             }
501             List<ComponentInstanceInterface> componentInstanceInterfaceList = componentInstanceInterfaces.get(componentInstanceId);
502             for (ComponentInstanceInterface componentInstanceInterface : componentInstanceInterfaceList) {
503                 if (componentInstanceInterface.getInterfaceId().equals(interfaceId)) {
504                     Map<String, OperationDataDefinition> operations = componentInstanceInterface.getOperations();
505                     if (MapUtils.isNotEmpty(operations) && operations.containsKey(operationId)) {
506                         ListDataDefinition<OperationInputDefinition> inputs = operations.get(operationId).getInputs();
507                         return Either.left(
508                             CollectionUtils.isEmpty(inputs.getListToscaDataDefinition()) ? new ArrayList<>() : inputs.getListToscaDataDefinition());
509                     }
510                 }
511             }
512             return Either.left(new ArrayList<>());
513         } catch (Exception e) {
514             LOGGER.error(EXCEPTION_OCCURRED_DURING_INTERFACE_OPERATION, "get", e);
515             janusGraphDao.rollback();
516             return Either.right(componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND));
517         } finally {
518             if (lockResult.isLeft() && lockResult.left().value()) {
519                 graphLockOperation
520                     .unlockComponent(storedComponent.getUniqueId(), NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue()));
521             }
522         }
523     }
524 }