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