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