Catalog alignment
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / validation / InterfaceOperationValidation.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
17 package org.openecomp.sdc.be.components.validation;
18
19 import com.google.common.collect.Sets;
20 import fj.data.Either;
21 import org.apache.commons.collections.CollectionUtils;
22 import org.apache.commons.collections.MapUtils;
23 import org.apache.commons.lang.StringUtils;
24 import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
25 import org.openecomp.sdc.be.components.utils.InterfaceOperationUtils;
26 import org.openecomp.sdc.be.dao.api.ActionStatus;
27 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
28 import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition;
29 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
30 import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition;
31 import org.openecomp.sdc.be.model.InterfaceDefinition;
32 import org.openecomp.sdc.be.model.Operation;
33 import org.openecomp.sdc.exception.ResponseFormat;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.springframework.stereotype.Component;
37
38 import java.util.ArrayList;
39 import java.util.Collection;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.Objects;
45 import java.util.Optional;
46 import java.util.Set;
47 import java.util.regex.Pattern;
48 import java.util.stream.Collectors;
49 import java.util.stream.Stream;
50
51 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationOutputName;
52 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOtherOperationOutputsOfComponent;
53 import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToComponentInput;
54 import static org.openecomp.sdc.be.components.utils.PropertiesUtils.isCapabilityProperty;
55
56 @Component("interfaceOperationValidation")
57 public class InterfaceOperationValidation {
58
59     private static final String TYPE_VALIDATION_REGEX = "^[a-zA-Z0-9_]{1,200}$";
60
61     private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
62
63     public Either<Boolean, ResponseFormat> validateInterfaceOperations(
64             InterfaceDefinition inputInterfaceDefinition, org.openecomp.sdc.be.model.Component component,
65             InterfaceDefinition storedInterfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes,
66             boolean isUpdate) {
67
68         Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType =
69                 validateAllowedOperationsOnGlobalInterfaceType(inputInterfaceDefinition, globalInterfaceTypes);
70         if (validateAllowedOperationsOnGlobalInterfaceType.isRight()) {
71             return validateAllowedOperationsOnGlobalInterfaceType;
72         }
73
74         Either<Boolean, ResponseFormat> validateOperationNameUniqueness =
75                 validateOperationNameUniquenessInCollection(inputInterfaceDefinition.getOperationsMap().values());
76         if (validateOperationNameUniqueness.isRight()) {
77             return validateOperationNameUniqueness;
78         }
79
80         for (Operation interfaceOperation : inputInterfaceDefinition.getOperationsMap().values()) {
81             Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
82                     interfaceOperation, storedInterfaceDefinition, inputInterfaceDefinition, component, isUpdate);
83             if (interfaceOperationValidatorResponse.isRight()) {
84                 return interfaceOperationValidatorResponse;
85             }
86         }
87
88         return Either.left(Boolean.TRUE);
89     }
90
91     public Either<Boolean, ResponseFormat> validateDeleteOperationContainsNoMappedOutput(
92             Operation interfaceOperationToDelete, org.openecomp.sdc.be.model.Component component,
93             InterfaceDefinition storedInterfaceDefinition) {
94         ResponseFormatManager responseFormatManager = getResponseFormatManager();
95         List<OperationOutputDefinition> existingOperationOutputs =
96                 getInterfaceOperationOutputs(interfaceOperationToDelete.getUniqueId(), component.getInterfaces());
97         if (existingOperationOutputs.isEmpty()) {
98             return Either.left(Boolean.TRUE);
99         }
100         String mappedOutputPrefix = storedInterfaceDefinition.getType() + "." + interfaceOperationToDelete.getName();
101         List<OperationInputDefinition> interfaceOperationInputs =
102                 getOtherOperationInputsOfComponent(mappedOutputPrefix, component.getInterfaces());
103         Set<String> mappedOutputsInDeletedOperation = new HashSet<>();
104         Set<String> existingOperationOutputNames = existingOperationOutputs.stream()
105                 .map(OperationOutputDefinition::getName)
106                 .collect(Collectors.toSet());
107         for (String existingOperationOutputName : existingOperationOutputNames) {
108             Set<String> matchedOutputsMappedToInputs = interfaceOperationInputs.stream()
109                     .filter(operationInputDefinition -> operationInputDefinition.getInputId()
110                             .equals(mappedOutputPrefix + "." + existingOperationOutputName))
111                     .map(operationInputDefinition -> getOperationOutputName(operationInputDefinition.getInputId()))
112                     .collect(Collectors.toSet());
113             mappedOutputsInDeletedOperation.addAll(matchedOutputsMappedToInputs);
114         }
115
116         if (CollectionUtils.isNotEmpty(mappedOutputsInDeletedOperation)) {
117             return getMappedOutputErrorResponse(responseFormatManager, mappedOutputsInDeletedOperation,
118                     "Cannot delete interface operation with output(s) '{}' mapped to another operation input",
119                     ActionStatus.INTERFACE_OPERATION_DELETE_WITH_MAPPED_OUTPUT);
120         }
121         return Either.left(Boolean.TRUE);
122     }
123
124     private Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType(
125             InterfaceDefinition inputInterfaceDefinition, InterfaceDefinition storedInterfaceDefinition,
126             Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate) {
127
128         boolean isInterfaceTypeExistInGlobalType =
129                 globalInterfaceTypes.values().stream().map(InterfaceDefinition::getType)
130                         .anyMatch(type -> type.equalsIgnoreCase(inputInterfaceDefinition.getType()));
131         if (!isInterfaceTypeExistInGlobalType
132                 && isValidOperationOnLocalInterfaceType(inputInterfaceDefinition, storedInterfaceDefinition,
133                 isUpdate)) {
134             return Either.right(getResponseFormatManager()
135                     .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE,
136                             inputInterfaceDefinition.getType()));
137         }
138
139         return Either.left(Boolean.TRUE);
140     }
141
142     private boolean isValidOperationOnLocalInterfaceType(InterfaceDefinition inputInterfaceDefinition,
143                                                          InterfaceDefinition storedInterfaceDefinition,
144                                                          boolean isUpdate) {
145         return inputInterfaceDefinition.getOperations().size() > 1
146                 || (!isUpdate && storedInterfaceDefinition != null
147                 && storedInterfaceDefinition.getType()
148                 .equalsIgnoreCase(inputInterfaceDefinition.getType()));
149     }
150
151     private Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType(
152             InterfaceDefinition interfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes) {
153
154         if (globalInterfaceTypes == null) {
155             return Either.left(Boolean.TRUE);
156         }
157         boolean isOperationValidOnGlobalInterfaceType = Stream.of(interfaceDefinition)
158                 .filter(interfaceDef -> globalInterfaceTypes.values().stream().anyMatch(interfaceDef1 ->
159                         interfaceDef1.getType().equalsIgnoreCase(interfaceDef.getType())))
160                 .flatMap(interfaceDef -> interfaceDef.getOperationsMap().values().stream().map(Operation::getName))
161                 .allMatch(operationName -> globalInterfaceTypes.values().stream()
162                         .flatMap(interfaceDef -> interfaceDef.getOperationsMap().keySet().stream())
163                         .anyMatch(opName -> opName.equalsIgnoreCase(operationName)));
164         if (!isOperationValidOnGlobalInterfaceType) {
165             return Either.right(getResponseFormatManager()
166                     .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE,
167                             interfaceDefinition.getType()));
168         }
169         return Either.left(Boolean.TRUE);
170     }
171
172     private Either<Boolean, ResponseFormat> validateOperationNameUniquenessInCollection(
173             Collection<Operation> operationList) {
174         HashSet<String> operationNames = new HashSet<>();
175         for (Operation operation : operationList) {
176             if (!operationNames.add(operation.getName())) {
177                 return Either.right(getResponseFormatManager()
178                                             .getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE,
179                                                     operation.getName()));
180             }
181         }
182         return Either.left(Boolean.TRUE);
183     }
184
185     private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
186             InterfaceDefinition storedInterfaceDefinition, InterfaceDefinition inputInterfaceDefinition,
187             org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
188
189         ResponseFormatManager responseFormatManager = getResponseFormatManager();
190         Either<Boolean, ResponseFormat> interfaceOperationTypeResponse =
191                 isInterfaceOperationTypeValid(interfaceOperation, responseFormatManager, storedInterfaceDefinition,
192                         isUpdate);
193         if (interfaceOperationTypeResponse.isRight()) {
194             return Either.right(interfaceOperationTypeResponse.right().value());
195         }
196
197         if (null != interfaceOperation.getInputs()
198                 && CollectionUtils.isNotEmpty(interfaceOperation.getInputs().getListToscaDataDefinition())) {
199             Either<Boolean, ResponseFormat> inputParametersResponse =
200                     validateInputParameters(interfaceOperation, responseFormatManager);
201             if (inputParametersResponse.isRight()) {
202                 return Either.right(inputParametersResponse.right().value());
203             }
204
205             Either<Boolean, ResponseFormat> inputPropertyExistInComponent =
206                     validateInputPropertyExistInComponent(interfaceOperation,
207                             inputInterfaceDefinition, component, responseFormatManager);
208             if (inputPropertyExistInComponent.isRight()) {
209                 return Either.right(inputPropertyExistInComponent.right().value());
210             }
211         }
212
213         if (null != interfaceOperation.getOutputs()
214                 && CollectionUtils.isNotEmpty(interfaceOperation.getOutputs().getListToscaDataDefinition())) {
215             Either<Boolean, ResponseFormat> outputParametersResponse =
216                     validateOutputParameters(interfaceOperation, responseFormatManager);
217             if (outputParametersResponse.isRight()) {
218                 return Either.right(outputParametersResponse.right().value());
219             }
220         }
221
222         if (MapUtils.isNotEmpty(component.getInterfaces()) && isUpdate) {
223             Either<Boolean, ResponseFormat> mappedOutputModifiedResponse =
224                     validateMappedOutputNotModified(interfaceOperation, component, inputInterfaceDefinition,
225                             responseFormatManager);
226             if (mappedOutputModifiedResponse.isRight()) {
227                 return Either.right(mappedOutputModifiedResponse.right().value());
228             }
229         }
230
231         return Either.left(Boolean.TRUE);
232     }
233
234
235     private Either<Boolean, ResponseFormat> validateMappedOutputNotModified(Operation interfaceOperation,
236             org.openecomp.sdc.be.model.Component component, InterfaceDefinition interfaceDefinition,
237             ResponseFormatManager responseFormatManager) {
238
239         List<OperationOutputDefinition> existingOperationOutputs =
240                 getInterfaceOperationOutputs(interfaceOperation.getUniqueId(), component.getInterfaces());
241         if (existingOperationOutputs.isEmpty()) {
242             return Either.left(Boolean.TRUE);
243         }
244         Set<String> existingOperationOutputNames = existingOperationOutputs.stream()
245                 .map(OperationOutputDefinition::getName)
246                 .collect(Collectors.toSet());
247
248         ListDataDefinition<OperationOutputDefinition> currentOutputs = interfaceOperation.getOutputs();
249         Set<String> currentOperationOutputNames = new HashSet<>();
250         if (currentOutputs != null && !currentOutputs.isEmpty()) {
251             currentOperationOutputNames = currentOutputs.getListToscaDataDefinition().stream()
252                     .map(OperationOutputDefinition::getName)
253                     .collect(Collectors.toSet());
254         }
255         String mappedOutputPrefix = interfaceDefinition.getType() + "." + interfaceOperation.getName();
256         //Get the deleted outputs (name changed also equivalent to deleted)
257         Set<String> deletedOutputs = Sets.difference(existingOperationOutputNames, currentOperationOutputNames);
258         Set<String> deletedMappedOutputs = getModifiedMappedOutputs(deletedOutputs, mappedOutputPrefix,
259                 component.getInterfaces());
260
261         if (CollectionUtils.isNotEmpty(deletedMappedOutputs)) {
262             return getMappedOutputErrorResponse(responseFormatManager, deletedMappedOutputs,
263                     "Cannot update or delete interface operation output(s) '{}' mapped to an operation input",
264                     ActionStatus.INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED);
265         }
266
267         if (currentOutputs != null && !currentOutputs.isEmpty()) {
268             //Get the unchanged outputs based on name to see if other attributes (type/mandatory) have not been changed
269             Set<String> unchangedOutputNames = Sets.intersection(existingOperationOutputNames,
270                     currentOperationOutputNames);
271             Set<String> modifiedOutputNames =
272                     getModifiedOutputNames(currentOutputs.getListToscaDataDefinition(),
273                             existingOperationOutputs, unchangedOutputNames);
274             Set<String> modifiedMappedOutputNames = getModifiedMappedOutputs(modifiedOutputNames, mappedOutputPrefix,
275                     component.getInterfaces());
276             if (CollectionUtils.isNotEmpty(modifiedMappedOutputNames)) {
277                 return getMappedOutputErrorResponse(responseFormatManager, modifiedMappedOutputNames,
278                         "Cannot update or delete interface operation output(s) '{}' mapped to an operation input",
279                         ActionStatus.INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED);
280             }
281         }
282
283         return Either.left(Boolean.TRUE);
284     }
285
286     private Set<String> getModifiedMappedOutputs(Set<String> modifiedOutputNames, String mappedOutputPrefix,
287                                                  Map<String, InterfaceDefinition> componentInterfaces) {
288         return modifiedOutputNames.stream()
289                 .filter(modifiedOutputName -> isMappedOutputModified(mappedOutputPrefix, modifiedOutputName,
290                         componentInterfaces))
291                 .map(InterfaceOperationUtils::getOperationOutputName)
292                 .collect(Collectors.toSet());
293     }
294
295     private boolean isMappedOutputModified(String mappedOutputPrefix, String outputName,
296                                            Map<String, InterfaceDefinition> componentInterfaces) {
297         List<OperationInputDefinition> interfaceOperationInputs =
298                 getOtherOperationInputsOfComponent(mappedOutputPrefix, componentInterfaces);
299         return interfaceOperationInputs.stream()
300                 .anyMatch(operationInputDefinition -> operationInputDefinition.getInputId()
301                         .equals(mappedOutputPrefix + "." + outputName));
302     }
303
304     private static Set<String> getModifiedOutputNames(List<OperationOutputDefinition> currentOperationOutputs,
305                                                       List<OperationOutputDefinition> existingOperationOutputs,
306                                                       Set<String> unchangedOutputNames) {
307         Set<String> modifiedOutputDefinitionNames = new HashSet<>();
308         Map<String, OperationOutputDefinition> newOutputMap = currentOperationOutputs.stream()
309                 .collect(Collectors.toMap(OperationOutputDefinition::getName,
310                         (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition));
311
312         Map<String, OperationOutputDefinition> existingOutputMap = existingOperationOutputs.stream()
313                 .collect(Collectors.toMap(OperationOutputDefinition::getName,
314                         (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition));
315
316         for (String outputName : unchangedOutputNames) {
317             OperationOutputDefinition existingOutputDefinition = existingOutputMap.get(outputName);
318             OperationOutputDefinition newOutputDefinition = newOutputMap.get(outputName);
319             if (!existingOutputDefinition.getType().equals(newOutputDefinition.getType())
320                         || !existingOutputDefinition.isRequired().equals(newOutputDefinition.isRequired())) {
321                 modifiedOutputDefinitionNames.add(outputName);
322             }
323         }
324         return modifiedOutputDefinitionNames;
325     }
326
327     private Either<Boolean, ResponseFormat> getMappedOutputErrorResponse(ResponseFormatManager responseFormatManager,
328                                                                          Set<String> modifiedMappedOutputs,
329                                                                          String message,
330                                                                          ActionStatus errorStatus) {
331         String modifiedOutputNameList = String.join(",", modifiedMappedOutputs);
332         LOGGER.error(message, modifiedOutputNameList);
333         ResponseFormat errorResponse = responseFormatManager.getResponseFormat(errorStatus, modifiedOutputNameList);
334         return Either.right(errorResponse);
335     }
336
337
338     protected ResponseFormatManager getResponseFormatManager() {
339         return ResponseFormatManager.getInstance();
340     }
341
342     private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
343                                                                           ResponseFormatManager responseFormatManager,
344                                                                           InterfaceDefinition interfaceDefinition,
345                                                                           boolean isUpdate) {
346
347         Either<Boolean, ResponseFormat> operationTypeEmptyEither =
348                 isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName());
349         if (operationTypeEmptyEither.isRight()) {
350             return Either.right(operationTypeEmptyEither.right().value());
351         }
352
353         Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
354                 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
355         if (operationTypeRegexValidationResponse.isRight()) {
356             return Either.right(operationTypeRegexValidationResponse.right().value());
357         }
358
359         Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
360                 interfaceDefinition, isUpdate);
361         if (operationTypeUniqueResponse.isRight()) {
362             return Either.right(operationTypeUniqueResponse.right().value());
363         }
364         if (!operationTypeUniqueResponse.left().value()) {
365             LOGGER.error("Interface Operation type  {} already in use ", interfaceOperation.getName());
366             ResponseFormat errorResponse = responseFormatManager.getResponseFormat(
367                     ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE, interfaceOperation.getName());
368             return Either.right(errorResponse);
369         }
370         return Either.left(Boolean.TRUE);
371     }
372
373     private Either<Boolean, ResponseFormat> validateInputParameters(Operation interfaceOperation,
374                                                                     ResponseFormatManager responseFormatManager) {
375         if (isInputParameterNameEmpty(interfaceOperation)) {
376             LOGGER.error("Interface operation input parameter name can't be empty");
377             ResponseFormat inputResponse =
378                     responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_MANDATORY);
379             return Either.right(inputResponse);
380         }
381
382         Either<Boolean, Set<String>> validateInputParametersUniqueResponse =
383                 isInputParametersUnique(interfaceOperation);
384         if (validateInputParametersUniqueResponse.isRight()) {
385             LOGGER.error("Interface operation input parameter names {} already in use",
386                     validateInputParametersUniqueResponse.right().value());
387             ResponseFormat inputResponse =
388                     responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE,
389                             validateInputParametersUniqueResponse.right().value().toString());
390             return Either.right(inputResponse);
391         }
392         return Either.left(Boolean.TRUE);
393     }
394
395     private Either<Boolean, ResponseFormat> validateOutputParameters(Operation interfaceOperation,
396                                                                      ResponseFormatManager responseFormatManager) {
397         if (isOutputParameterNameEmpty(interfaceOperation)) {
398             LOGGER.error("Interface operation output parameter name can't be empty");
399             ResponseFormat inputResponse =
400                     responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY);
401             return Either.right(inputResponse);
402         }
403
404         Either<Boolean, Set<String>> validateOutputParametersUniqueResponse =
405                 isOutputParametersUnique(interfaceOperation);
406         if (validateOutputParametersUniqueResponse.isRight()) {
407             LOGGER.error("Interface operation output parameter names {} already in use",
408                     validateOutputParametersUniqueResponse.right().value());
409             ResponseFormat inputResponse =
410                     responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE,
411                             validateOutputParametersUniqueResponse.right().value().toString());
412             return Either.right(inputResponse);
413         }
414         return Either.left(Boolean.TRUE);
415     }
416
417     private Either<Boolean, ResponseFormat> isOperationTypeEmpty(ResponseFormatManager responseFormatManager,
418             String operationType) {
419         if (StringUtils.isEmpty(operationType)) {
420             LOGGER.error("Interface Operation type is mandatory");
421             ResponseFormat errorResponse =
422                     responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_MANDATORY);
423             return Either.right(errorResponse);
424         }
425         return Either.left(Boolean.TRUE);
426     }
427
428     private Either<Boolean, ResponseFormat> isOperationTypeRegexValid(ResponseFormatManager responseFormatManager,
429             String operationType) {
430         if (!isValidOperationType(operationType)) {
431             LOGGER.error("Interface Operation type {} is invalid, Operation type should not contain"
432                                  + "Special character, space, numbers and  should not be greater than 200 characters",
433                     operationType);
434             ResponseFormat errorResponse = responseFormatManager
435                                                    .getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_INVALID,
436                                                            operationType);
437             return Either.right(errorResponse);
438         }
439         return Either.left(Boolean.TRUE);
440     }
441
442     private Either<Boolean, ResponseFormat> validateOperationTypeUnique(Operation interfaceOperation,
443             InterfaceDefinition interfaceDefinition, boolean isUpdate) {
444         boolean isOperationTypeUnique = false;
445
446         if (interfaceDefinition == null || CollectionUtils.isEmpty(interfaceDefinition.getOperationsMap().values())) {
447             return Either.left(true);
448         }
449
450         Map<String, String> operationTypes = new HashMap<>();
451         interfaceDefinition.getOperationsMap().values()
452                 .forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()));
453
454         if (!operationTypes.values().contains(interfaceOperation.getName())) {
455             isOperationTypeUnique = true;
456         }
457         if (!isOperationTypeUnique && isUpdate) {
458             Optional<String> id = operationTypes.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(),
459                     interfaceOperation.getName())).map(Map.Entry::getKey).findAny();
460             if (id.isPresent() && id.get().equalsIgnoreCase(interfaceOperation.getUniqueId())) {
461                 isOperationTypeUnique = true;
462             }
463         }
464
465         return Either.left(isOperationTypeUnique);
466     }
467
468     private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
469         return operationDataDefinition.getInputs().getListToscaDataDefinition().stream().anyMatch(
470                 inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
471     }
472
473
474     private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) {
475         Set<String> inputParamNamesSet = new HashSet<>();
476         Set<String> duplicateParamNamesToReturn = new HashSet<>();
477         operationDataDefinition.getInputs().getListToscaDataDefinition()
478                                .forEach(inputParam -> {
479                                    if (!inputParamNamesSet.add(inputParam.getName().trim())) {
480                                        duplicateParamNamesToReturn.add(inputParam.getName().trim());
481                                    }
482                                });
483         if (!duplicateParamNamesToReturn.isEmpty()) {
484             return Either.right(duplicateParamNamesToReturn);
485         }
486         return Either.left(Boolean.TRUE);
487     }
488
489     private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
490         return operationDataDefinition.getOutputs().getListToscaDataDefinition().stream().anyMatch(
491                 outputParam -> outputParam.getName() == null || outputParam.getName().trim().equals(StringUtils.EMPTY));
492     }
493
494     private Either<Boolean, Set<String>> isOutputParametersUnique(Operation operationDataDefinition) {
495         Set<String> outputParamNamesSet = new HashSet<>();
496         Set<String> duplicateParamNamesToReturn = new HashSet<>();
497         operationDataDefinition.getOutputs().getListToscaDataDefinition()
498                                .forEach(outputParam -> {
499                                    if (!outputParamNamesSet.add(outputParam.getName().trim())) {
500                                        duplicateParamNamesToReturn.add(outputParam.getName().trim());
501                                    }
502                                });
503         if (!duplicateParamNamesToReturn.isEmpty()) {
504             return Either.right(duplicateParamNamesToReturn);
505         }
506         return Either.left(Boolean.TRUE);
507     }
508
509     private  Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation,
510             InterfaceDefinition inputInterfaceDefinition, org.openecomp.sdc.be.model.Component component,
511             ResponseFormatManager responseFormatManager) {
512
513         boolean isOperationInputToInputPropertyMappingValid = false;
514         boolean isOperationInputToOtherOperationOutputMappingValid = false;
515         String mappingName = "";
516         List<OperationInputDefinition> inputListToscaDataDefinition =
517                 operation.getInputs().getListToscaDataDefinition();
518         for (OperationInputDefinition inputDefinition : inputListToscaDataDefinition) {
519             if (isOperationInputMappedToComponentInput(inputDefinition, component.getInputs())
520                     || isCapabilityProperty(inputDefinition.getInputId(), component).isPresent()) {
521                 isOperationInputToInputPropertyMappingValid = true;
522             } else {
523                 mappingName = inputDefinition.getInputId().contains(".")
524                         ? inputDefinition.getInputId().substring(inputDefinition.getInputId().lastIndexOf('.') + 1)
525                         : inputDefinition.getInputId();
526                 break;
527             }
528         }
529         if (isOperationInputToInputPropertyMappingValid) {
530             return Either.left(Boolean.TRUE);
531         }
532
533         //Mapped property not found in the component properties.. Check in other operation output parameters of
534         // component (other operation => not having the same full name)
535         String actualOperationIdentifier = inputInterfaceDefinition.getType() + "." + operation.getName();
536         ListDataDefinition<OperationOutputDefinition> outputListDataDefinition =
537                 getOtherOperationOutputsOfComponent(actualOperationIdentifier, component.getInterfaces());
538
539         List<OperationOutputDefinition> componentOutputsFromOtherOperations =
540                 outputListDataDefinition.getListToscaDataDefinition();
541         if (validateOutputExistsInComponent(mappingName, componentOutputsFromOtherOperations)) {
542             isOperationInputToOtherOperationOutputMappingValid = true;
543         } else {
544             //Get the output parameter display name from the full name
545             mappingName = getOperationOutputName(mappingName);
546         }
547
548         if (!isOperationInputToOtherOperationOutputMappingValid) {
549             LOGGER.error("Interface operation input parameter property {} not found in component input properties or"
550                    + "capability properties or  outputs of other operations.", mappingName);
551             ResponseFormat inputResponse = responseFormatManager
552                     .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT,
553                             mappingName, component.getComponentType().getValue());
554             return Either.right(inputResponse);
555         }
556         return Either.left(Boolean.TRUE);
557     }
558
559     private boolean validateOutputExistsInComponent(String mappedOutputName,
560                                                     List<OperationOutputDefinition> outputs) {
561         return outputs.stream()
562                 .anyMatch(output -> output.getName().equals(mappedOutputName));
563     }
564
565     /**
566      * Get the input definitions of other operations of the component from current as well as other interfaces.
567      * @param currentOperationIdentifier Identifier for the request operation (interface_name.operation_name)
568      * @param componentInterfaces Interfaces of the component
569      */
570     private List<OperationInputDefinition> getOtherOperationInputsOfComponent(String currentOperationIdentifier,
571                                                                               Map<String, InterfaceDefinition>
572                                                                                       componentInterfaces) {
573         List<OperationInputDefinition> otherOperationInputs = new ArrayList<>();
574         if (MapUtils.isEmpty(componentInterfaces)) {
575             return otherOperationInputs;
576         }
577         for (Map.Entry<String, InterfaceDefinition> interfaceDefinitionEntry : componentInterfaces.entrySet()) {
578             final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations();
579             if (MapUtils.isEmpty(operations)) {
580                 continue;
581             }
582             for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
583                 ListDataDefinition<OperationInputDefinition> inputs = operationEntry.getValue().getInputs();
584                 String expectedOperationIdentifier =
585                         interfaceDefinitionEntry.getValue().getType() + "." + operationEntry.getValue().getName();
586                 if (!currentOperationIdentifier.equals(expectedOperationIdentifier) && Objects.nonNull(inputs) && !inputs.isEmpty()) {
587                     otherOperationInputs.addAll(inputs.getListToscaDataDefinition());
588                 }
589             }
590         }
591         return otherOperationInputs;
592     }
593
594     /**
595      * Get the output of an operation in an interface.
596      * @param inputOperationId Unique identifier for the request operation
597      * @param componentInterfaces Interfaces of the component
598      */
599     private List<OperationOutputDefinition> getInterfaceOperationOutputs(String inputOperationId,
600                                                                          Map<String, InterfaceDefinition>
601                                                                                  componentInterfaces) {
602         List<OperationOutputDefinition> operationOutputDefinitions = new ArrayList<>();
603         if (MapUtils.isEmpty(componentInterfaces)) {
604             return operationOutputDefinitions;
605         }
606         for (Map.Entry<String, InterfaceDefinition> interfaceDefinitionEntry : componentInterfaces.entrySet()) {
607             final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations();
608             if (MapUtils.isEmpty(operations)) {
609                 continue;
610             }
611             for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
612                 String expectedOperationId = operationEntry.getValue().getUniqueId();
613                 if (expectedOperationId.equals(inputOperationId)) {
614                     ListDataDefinition<OperationOutputDefinition> operationOutputs =
615                             operationEntry.getValue().getOutputs();
616                     return (Objects.isNull(operationOutputs) || operationOutputs.isEmpty())
617                             ? operationOutputDefinitions
618                             : operationOutputs.getListToscaDataDefinition();
619                 }
620             }
621         }
622         return operationOutputDefinitions;
623     }
624
625     private boolean isValidOperationType(String operationType) {
626         return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
627     }
628
629 }