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