2 * Copyright © 2016-2018 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.openecomp.sdc.be.components.validation;
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;
24 import com.google.common.collect.Sets;
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;
32 import java.util.Objects;
33 import java.util.Optional;
35 import java.util.regex.Pattern;
36 import java.util.stream.Collectors;
37 import java.util.stream.Stream;
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;
57 @Component("interfaceOperationValidation")
58 public class InterfaceOperationValidation {
60 private static final String TYPE_VALIDATION_REGEX = "^[a-zA-Z0-9_]{1,200}$";
62 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
64 public Either<Boolean, ResponseFormat> validateInterfaceOperations(
65 InterfaceDefinition inputInterfaceDefinition, org.openecomp.sdc.be.model.Component component,
66 InterfaceDefinition storedInterfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes,
69 Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType =
70 validateAllowedOperationsOnGlobalInterfaceType(inputInterfaceDefinition, globalInterfaceTypes);
71 if (validateAllowedOperationsOnGlobalInterfaceType.isRight()) {
72 return validateAllowedOperationsOnGlobalInterfaceType;
75 Either<Boolean, ResponseFormat> validateOperationNameUniqueness =
76 validateOperationNameUniquenessInCollection(inputInterfaceDefinition.getOperationsMap().values());
77 if (validateOperationNameUniqueness.isRight()) {
78 return validateOperationNameUniqueness;
81 for (Operation interfaceOperation : inputInterfaceDefinition.getOperationsMap().values()) {
82 Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
83 interfaceOperation, storedInterfaceDefinition, inputInterfaceDefinition, component, isUpdate);
84 if (interfaceOperationValidatorResponse.isRight()) {
85 return interfaceOperationValidatorResponse;
89 return Either.left(Boolean.TRUE);
92 public Either<Boolean, ResponseFormat> validateDeleteOperationContainsNoMappedOutput(
93 Operation interfaceOperationToDelete, org.openecomp.sdc.be.model.Component component,
94 InterfaceDefinition storedInterfaceDefinition) {
95 ResponseFormatManager responseFormatManager = getResponseFormatManager();
96 List<OperationOutputDefinition> existingOperationOutputs =
97 getInterfaceOperationOutputs(interfaceOperationToDelete.getUniqueId(), component.getInterfaces());
98 if (existingOperationOutputs.isEmpty()) {
99 return Either.left(Boolean.TRUE);
101 String mappedOutputPrefix = storedInterfaceDefinition.getType() + "." + interfaceOperationToDelete.getName();
102 List<OperationInputDefinition> interfaceOperationInputs =
103 getOtherOperationInputsOfComponent(mappedOutputPrefix, component.getInterfaces());
104 Set<String> mappedOutputsInDeletedOperation = new HashSet<>();
105 Set<String> existingOperationOutputNames = existingOperationOutputs.stream()
106 .map(OperationOutputDefinition::getName)
107 .collect(Collectors.toSet());
108 for (String existingOperationOutputName : existingOperationOutputNames) {
109 Set<String> matchedOutputsMappedToInputs = interfaceOperationInputs.stream()
110 .filter(operationInputDefinition -> operationInputDefinition.getInputId()
111 .equals(mappedOutputPrefix + "." + existingOperationOutputName))
112 .map(operationInputDefinition -> getOperationOutputName(operationInputDefinition.getInputId()))
113 .collect(Collectors.toSet());
114 mappedOutputsInDeletedOperation.addAll(matchedOutputsMappedToInputs);
117 if (CollectionUtils.isNotEmpty(mappedOutputsInDeletedOperation)) {
118 return getMappedOutputErrorResponse(responseFormatManager, mappedOutputsInDeletedOperation,
119 "Cannot delete interface operation with output(s) '{}' mapped to another operation input",
120 ActionStatus.INTERFACE_OPERATION_DELETE_WITH_MAPPED_OUTPUT);
122 return Either.left(Boolean.TRUE);
125 private Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType(
126 InterfaceDefinition inputInterfaceDefinition, InterfaceDefinition storedInterfaceDefinition,
127 Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate) {
129 boolean isInterfaceTypeExistInGlobalType =
130 globalInterfaceTypes.values().stream().map(InterfaceDefinition::getType)
131 .anyMatch(type -> type.equalsIgnoreCase(inputInterfaceDefinition.getType()));
132 if (!isInterfaceTypeExistInGlobalType
133 && isValidOperationOnLocalInterfaceType(inputInterfaceDefinition, storedInterfaceDefinition,
135 return Either.right(getResponseFormatManager()
136 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE,
137 inputInterfaceDefinition.getType()));
140 return Either.left(Boolean.TRUE);
143 private boolean isValidOperationOnLocalInterfaceType(InterfaceDefinition inputInterfaceDefinition,
144 InterfaceDefinition storedInterfaceDefinition,
146 return inputInterfaceDefinition.getOperations().size() > 1
147 || (!isUpdate && storedInterfaceDefinition != null
148 && storedInterfaceDefinition.getType()
149 .equalsIgnoreCase(inputInterfaceDefinition.getType()));
152 private Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType(
153 InterfaceDefinition interfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes) {
155 if (globalInterfaceTypes == null) {
156 return Either.left(Boolean.TRUE);
158 boolean isOperationValidOnGlobalInterfaceType = Stream.of(interfaceDefinition)
159 .filter(interfaceDef -> globalInterfaceTypes.values().stream().anyMatch(interfaceDef1 ->
160 interfaceDef1.getType().equalsIgnoreCase(interfaceDef.getType())))
161 .flatMap(interfaceDef -> interfaceDef.getOperationsMap().values().stream().map(Operation::getName))
162 .allMatch(operationName -> globalInterfaceTypes.values().stream()
163 .flatMap(interfaceDef -> interfaceDef.getOperationsMap().keySet().stream())
164 .anyMatch(opName -> opName.equalsIgnoreCase(operationName)));
165 if (!isOperationValidOnGlobalInterfaceType) {
166 return Either.right(getResponseFormatManager()
167 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE,
168 interfaceDefinition.getType()));
170 return Either.left(Boolean.TRUE);
173 private Either<Boolean, ResponseFormat> validateOperationNameUniquenessInCollection(
174 Collection<Operation> operationList) {
175 HashSet<String> operationNames = new HashSet<>();
176 for (Operation operation : operationList) {
177 if (!operationNames.add(operation.getName())) {
178 return Either.right(getResponseFormatManager()
179 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE,
180 operation.getName()));
183 return Either.left(Boolean.TRUE);
186 private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
187 InterfaceDefinition storedInterfaceDefinition, InterfaceDefinition inputInterfaceDefinition,
188 org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
190 ResponseFormatManager responseFormatManager = getResponseFormatManager();
191 Either<Boolean, ResponseFormat> interfaceOperationTypeResponse =
192 isInterfaceOperationTypeValid(interfaceOperation, responseFormatManager, storedInterfaceDefinition,
194 if (interfaceOperationTypeResponse.isRight()) {
195 return Either.right(interfaceOperationTypeResponse.right().value());
198 if (null != interfaceOperation.getInputs()
199 && CollectionUtils.isNotEmpty(interfaceOperation.getInputs().getListToscaDataDefinition())) {
200 Either<Boolean, ResponseFormat> inputParametersResponse =
201 validateInputParameters(interfaceOperation, responseFormatManager);
202 if (inputParametersResponse.isRight()) {
203 return Either.right(inputParametersResponse.right().value());
206 Either<Boolean, ResponseFormat> inputPropertyExistInComponent =
207 validateInputPropertyExistInComponent(interfaceOperation,
208 inputInterfaceDefinition, component, responseFormatManager);
209 if (inputPropertyExistInComponent.isRight()) {
210 return Either.right(inputPropertyExistInComponent.right().value());
214 if (null != interfaceOperation.getOutputs()
215 && CollectionUtils.isNotEmpty(interfaceOperation.getOutputs().getListToscaDataDefinition())) {
216 Either<Boolean, ResponseFormat> outputParametersResponse =
217 validateOutputParameters(interfaceOperation, responseFormatManager);
218 if (outputParametersResponse.isRight()) {
219 return Either.right(outputParametersResponse.right().value());
223 if (MapUtils.isNotEmpty(component.getInterfaces()) && isUpdate) {
224 Either<Boolean, ResponseFormat> mappedOutputModifiedResponse =
225 validateMappedOutputNotModified(interfaceOperation, component, inputInterfaceDefinition,
226 responseFormatManager);
227 if (mappedOutputModifiedResponse.isRight()) {
228 return Either.right(mappedOutputModifiedResponse.right().value());
232 return Either.left(Boolean.TRUE);
236 private Either<Boolean, ResponseFormat> validateMappedOutputNotModified(Operation interfaceOperation,
237 org.openecomp.sdc.be.model.Component component, InterfaceDefinition interfaceDefinition,
238 ResponseFormatManager responseFormatManager) {
240 List<OperationOutputDefinition> existingOperationOutputs =
241 getInterfaceOperationOutputs(interfaceOperation.getUniqueId(), component.getInterfaces());
242 if (existingOperationOutputs.isEmpty()) {
243 return Either.left(Boolean.TRUE);
245 Set<String> existingOperationOutputNames = existingOperationOutputs.stream()
246 .map(OperationOutputDefinition::getName)
247 .collect(Collectors.toSet());
249 ListDataDefinition<OperationOutputDefinition> currentOutputs = interfaceOperation.getOutputs();
250 Set<String> currentOperationOutputNames = new HashSet<>();
251 if (currentOutputs != null && !currentOutputs.isEmpty()) {
252 currentOperationOutputNames = currentOutputs.getListToscaDataDefinition().stream()
253 .map(OperationOutputDefinition::getName)
254 .collect(Collectors.toSet());
256 String mappedOutputPrefix = interfaceDefinition.getType() + "." + interfaceOperation.getName();
257 //Get the deleted outputs (name changed also equivalent to deleted)
258 Set<String> deletedOutputs = Sets.difference(existingOperationOutputNames, currentOperationOutputNames);
259 Set<String> deletedMappedOutputs = getModifiedMappedOutputs(deletedOutputs, mappedOutputPrefix,
260 component.getInterfaces());
262 if (CollectionUtils.isNotEmpty(deletedMappedOutputs)) {
263 return getMappedOutputErrorResponse(responseFormatManager, deletedMappedOutputs,
264 "Cannot update or delete interface operation output(s) '{}' mapped to an operation input",
265 ActionStatus.INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED);
268 if (currentOutputs != null && !currentOutputs.isEmpty()) {
269 //Get the unchanged outputs based on name to see if other attributes (type/mandatory) have not been changed
270 Set<String> unchangedOutputNames = Sets.intersection(existingOperationOutputNames,
271 currentOperationOutputNames);
272 Set<String> modifiedOutputNames =
273 getModifiedOutputNames(currentOutputs.getListToscaDataDefinition(),
274 existingOperationOutputs, unchangedOutputNames);
275 Set<String> modifiedMappedOutputNames = getModifiedMappedOutputs(modifiedOutputNames, mappedOutputPrefix,
276 component.getInterfaces());
277 if (CollectionUtils.isNotEmpty(modifiedMappedOutputNames)) {
278 return getMappedOutputErrorResponse(responseFormatManager, modifiedMappedOutputNames,
279 "Cannot update or delete interface operation output(s) '{}' mapped to an operation input",
280 ActionStatus.INTERFACE_OPERATION_MAPPED_OUTPUT_MODIFIED);
284 return Either.left(Boolean.TRUE);
287 private Set<String> getModifiedMappedOutputs(Set<String> modifiedOutputNames, String mappedOutputPrefix,
288 Map<String, InterfaceDefinition> componentInterfaces) {
289 return modifiedOutputNames.stream()
290 .filter(modifiedOutputName -> isMappedOutputModified(mappedOutputPrefix, modifiedOutputName,
291 componentInterfaces))
292 .map(InterfaceOperationUtils::getOperationOutputName)
293 .collect(Collectors.toSet());
296 private boolean isMappedOutputModified(String mappedOutputPrefix, String outputName,
297 Map<String, InterfaceDefinition> componentInterfaces) {
298 List<OperationInputDefinition> interfaceOperationInputs =
299 getOtherOperationInputsOfComponent(mappedOutputPrefix, componentInterfaces);
300 return interfaceOperationInputs.stream()
301 .anyMatch(operationInputDefinition -> operationInputDefinition.getInputId()
302 .equals(mappedOutputPrefix + "." + outputName));
305 private static Set<String> getModifiedOutputNames(List<OperationOutputDefinition> currentOperationOutputs,
306 List<OperationOutputDefinition> existingOperationOutputs,
307 Set<String> unchangedOutputNames) {
308 Set<String> modifiedOutputDefinitionNames = new HashSet<>();
309 Map<String, OperationOutputDefinition> newOutputMap = currentOperationOutputs.stream()
310 .collect(Collectors.toMap(OperationOutputDefinition::getName,
311 (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition));
313 Map<String, OperationOutputDefinition> existingOutputMap = existingOperationOutputs.stream()
314 .collect(Collectors.toMap(OperationOutputDefinition::getName,
315 (OperationOutputDefinition operationOutputDefinition) -> operationOutputDefinition));
317 for (String outputName : unchangedOutputNames) {
318 OperationOutputDefinition existingOutputDefinition = existingOutputMap.get(outputName);
319 OperationOutputDefinition newOutputDefinition = newOutputMap.get(outputName);
320 if (!existingOutputDefinition.getType().equals(newOutputDefinition.getType())
321 || !existingOutputDefinition.isRequired().equals(newOutputDefinition.isRequired())) {
322 modifiedOutputDefinitionNames.add(outputName);
325 return modifiedOutputDefinitionNames;
328 private Either<Boolean, ResponseFormat> getMappedOutputErrorResponse(ResponseFormatManager responseFormatManager,
329 Set<String> modifiedMappedOutputs,
331 ActionStatus errorStatus) {
332 String modifiedOutputNameList = String.join(",", modifiedMappedOutputs);
333 LOGGER.error(message, modifiedOutputNameList);
334 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(errorStatus, modifiedOutputNameList);
335 return Either.right(errorResponse);
339 protected ResponseFormatManager getResponseFormatManager() {
340 return ResponseFormatManager.getInstance();
343 private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
344 ResponseFormatManager responseFormatManager,
345 InterfaceDefinition interfaceDefinition,
348 Either<Boolean, ResponseFormat> operationTypeEmptyEither =
349 isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName());
350 if (operationTypeEmptyEither.isRight()) {
351 return Either.right(operationTypeEmptyEither.right().value());
354 Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
355 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
356 if (operationTypeRegexValidationResponse.isRight()) {
357 return Either.right(operationTypeRegexValidationResponse.right().value());
360 Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
361 interfaceDefinition, isUpdate);
362 if (operationTypeUniqueResponse.isRight()) {
363 return Either.right(operationTypeUniqueResponse.right().value());
365 if (!operationTypeUniqueResponse.left().value()) {
366 LOGGER.error("Interface Operation type {} already in use ", interfaceOperation.getName());
367 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(
368 ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE, interfaceOperation.getName());
369 return Either.right(errorResponse);
371 return Either.left(Boolean.TRUE);
374 private Either<Boolean, ResponseFormat> validateInputParameters(Operation interfaceOperation,
375 ResponseFormatManager responseFormatManager) {
376 if (isInputParameterNameEmpty(interfaceOperation)) {
377 LOGGER.error("Interface operation input parameter name can't be empty");
378 ResponseFormat inputResponse =
379 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_MANDATORY);
380 return Either.right(inputResponse);
383 Either<Boolean, Set<String>> validateInputParametersUniqueResponse =
384 isInputParametersUnique(interfaceOperation);
385 if (validateInputParametersUniqueResponse.isRight()) {
386 LOGGER.error("Interface operation input parameter names {} already in use",
387 validateInputParametersUniqueResponse.right().value());
388 ResponseFormat inputResponse =
389 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE,
390 validateInputParametersUniqueResponse.right().value().toString());
391 return Either.right(inputResponse);
393 return Either.left(Boolean.TRUE);
396 private Either<Boolean, ResponseFormat> validateOutputParameters(Operation interfaceOperation,
397 ResponseFormatManager responseFormatManager) {
398 if (isOutputParameterNameEmpty(interfaceOperation)) {
399 LOGGER.error("Interface operation output parameter name can't be empty");
400 ResponseFormat inputResponse =
401 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY);
402 return Either.right(inputResponse);
405 Either<Boolean, Set<String>> validateOutputParametersUniqueResponse =
406 isOutputParametersUnique(interfaceOperation);
407 if (validateOutputParametersUniqueResponse.isRight()) {
408 LOGGER.error("Interface operation output parameter names {} already in use",
409 validateOutputParametersUniqueResponse.right().value());
410 ResponseFormat inputResponse =
411 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE,
412 validateOutputParametersUniqueResponse.right().value().toString());
413 return Either.right(inputResponse);
415 return Either.left(Boolean.TRUE);
418 private Either<Boolean, ResponseFormat> isOperationTypeEmpty(ResponseFormatManager responseFormatManager,
419 String operationType) {
420 if (StringUtils.isEmpty(operationType)) {
421 LOGGER.error("Interface Operation type is mandatory");
422 ResponseFormat errorResponse =
423 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_MANDATORY);
424 return Either.right(errorResponse);
426 return Either.left(Boolean.TRUE);
429 private Either<Boolean, ResponseFormat> isOperationTypeRegexValid(ResponseFormatManager responseFormatManager,
430 String operationType) {
431 if (!isValidOperationType(operationType)) {
432 LOGGER.error("Interface Operation type {} is invalid, Operation type should not contain"
433 + "Special character, space, numbers and should not be greater than 200 characters",
435 ResponseFormat errorResponse = responseFormatManager
436 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_INVALID,
438 return Either.right(errorResponse);
440 return Either.left(Boolean.TRUE);
443 private Either<Boolean, ResponseFormat> validateOperationTypeUnique(Operation interfaceOperation,
444 InterfaceDefinition interfaceDefinition, boolean isUpdate) {
445 boolean isOperationTypeUnique = false;
447 if (interfaceDefinition == null || CollectionUtils.isEmpty(interfaceDefinition.getOperationsMap().values())) {
448 return Either.left(true);
451 Map<String, String> operationTypes = new HashMap<>();
452 interfaceDefinition.getOperationsMap().values()
453 .forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()));
455 if (!operationTypes.values().contains(interfaceOperation.getName())) {
456 isOperationTypeUnique = true;
458 if (!isOperationTypeUnique && isUpdate) {
459 Optional<String> id = operationTypes.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(),
460 interfaceOperation.getName())).map(Map.Entry::getKey).findAny();
461 if (id.isPresent() && id.get().equalsIgnoreCase(interfaceOperation.getUniqueId())) {
462 isOperationTypeUnique = true;
466 return Either.left(isOperationTypeUnique);
469 private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
470 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream().anyMatch(
471 inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
475 private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) {
476 Set<String> inputParamNamesSet = new HashSet<>();
477 Set<String> duplicateParamNamesToReturn = new HashSet<>();
478 operationDataDefinition.getInputs().getListToscaDataDefinition()
479 .forEach(inputParam -> {
480 if (!inputParamNamesSet.add(inputParam.getName().trim())) {
481 duplicateParamNamesToReturn.add(inputParam.getName().trim());
484 if (!duplicateParamNamesToReturn.isEmpty()) {
485 return Either.right(duplicateParamNamesToReturn);
487 return Either.left(Boolean.TRUE);
490 private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
491 return operationDataDefinition.getOutputs().getListToscaDataDefinition().stream().anyMatch(
492 outputParam -> outputParam.getName() == null || outputParam.getName().trim().equals(StringUtils.EMPTY));
495 private Either<Boolean, Set<String>> isOutputParametersUnique(Operation operationDataDefinition) {
496 Set<String> outputParamNamesSet = new HashSet<>();
497 Set<String> duplicateParamNamesToReturn = new HashSet<>();
498 operationDataDefinition.getOutputs().getListToscaDataDefinition()
499 .forEach(outputParam -> {
500 if (!outputParamNamesSet.add(outputParam.getName().trim())) {
501 duplicateParamNamesToReturn.add(outputParam.getName().trim());
504 if (!duplicateParamNamesToReturn.isEmpty()) {
505 return Either.right(duplicateParamNamesToReturn);
507 return Either.left(Boolean.TRUE);
510 private Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation,
511 InterfaceDefinition inputInterfaceDefinition, org.openecomp.sdc.be.model.Component component,
512 ResponseFormatManager responseFormatManager) {
514 boolean isOperationInputToInputPropertyMappingValid = false;
515 boolean isOperationInputToOtherOperationOutputMappingValid = false;
516 String mappingName = "";
517 List<OperationInputDefinition> inputListToscaDataDefinition =
518 operation.getInputs().getListToscaDataDefinition();
519 for (OperationInputDefinition inputDefinition : inputListToscaDataDefinition) {
520 if (isOperationInputMappedToComponentInput(inputDefinition, component.getInputs())
521 || isCapabilityProperty(inputDefinition.getInputId(), component).isPresent()) {
522 isOperationInputToInputPropertyMappingValid = true;
524 mappingName = inputDefinition.getInputId().contains(".")
525 ? inputDefinition.getInputId().substring(inputDefinition.getInputId().lastIndexOf('.') + 1)
526 : inputDefinition.getInputId();
530 if (isOperationInputToInputPropertyMappingValid) {
531 return Either.left(Boolean.TRUE);
534 //Mapped property not found in the component properties.. Check in other operation output parameters of
535 // component (other operation => not having the same full name)
536 String actualOperationIdentifier = inputInterfaceDefinition.getType() + "." + operation.getName();
537 ListDataDefinition<OperationOutputDefinition> outputListDataDefinition =
538 getOtherOperationOutputsOfComponent(actualOperationIdentifier, component.getInterfaces());
540 List<OperationOutputDefinition> componentOutputsFromOtherOperations =
541 outputListDataDefinition.getListToscaDataDefinition();
542 if (validateOutputExistsInComponent(mappingName, componentOutputsFromOtherOperations)) {
543 isOperationInputToOtherOperationOutputMappingValid = true;
545 //Get the output parameter display name from the full name
546 mappingName = getOperationOutputName(mappingName);
549 if (!isOperationInputToOtherOperationOutputMappingValid) {
550 LOGGER.error("Interface operation input parameter property {} not found in component input properties or"
551 + "capability properties or outputs of other operations.", mappingName);
552 ResponseFormat inputResponse = responseFormatManager
553 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT,
554 mappingName, component.getComponentType().getValue());
555 return Either.right(inputResponse);
557 return Either.left(Boolean.TRUE);
560 private boolean validateOutputExistsInComponent(String mappedOutputName,
561 List<OperationOutputDefinition> outputs) {
562 return outputs.stream()
563 .anyMatch(output -> output.getName().equals(mappedOutputName));
567 * Get the input definitions of other operations of the component from current as well as other interfaces.
568 * @param currentOperationIdentifier Identifier for the request operation (interface_name.operation_name)
569 * @param componentInterfaces Interfaces of the component
571 private List<OperationInputDefinition> getOtherOperationInputsOfComponent(String currentOperationIdentifier,
572 Map<String, InterfaceDefinition>
573 componentInterfaces) {
574 List<OperationInputDefinition> otherOperationInputs = new ArrayList<>();
575 if (MapUtils.isEmpty(componentInterfaces)) {
576 return otherOperationInputs;
578 for (Map.Entry<String, InterfaceDefinition> interfaceDefinitionEntry : componentInterfaces.entrySet()) {
579 final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations();
580 if (MapUtils.isEmpty(operations)) {
583 for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
584 ListDataDefinition<OperationInputDefinition> inputs = operationEntry.getValue().getInputs();
585 String expectedOperationIdentifier =
586 interfaceDefinitionEntry.getValue().getType() + "." + operationEntry.getValue().getName();
587 if (!currentOperationIdentifier.equals(expectedOperationIdentifier) && Objects.nonNull(inputs) && !inputs.isEmpty()) {
588 otherOperationInputs.addAll(inputs.getListToscaDataDefinition());
592 return otherOperationInputs;
596 * Get the output of an operation in an interface.
597 * @param inputOperationId Unique identifier for the request operation
598 * @param componentInterfaces Interfaces of the component
600 private List<OperationOutputDefinition> getInterfaceOperationOutputs(String inputOperationId,
601 Map<String, InterfaceDefinition>
602 componentInterfaces) {
603 List<OperationOutputDefinition> operationOutputDefinitions = new ArrayList<>();
604 if (MapUtils.isEmpty(componentInterfaces)) {
605 return operationOutputDefinitions;
607 for (Map.Entry<String, InterfaceDefinition> interfaceDefinitionEntry : componentInterfaces.entrySet()) {
608 final Map<String, OperationDataDefinition> operations = interfaceDefinitionEntry.getValue().getOperations();
609 if (MapUtils.isEmpty(operations)) {
612 for (Map.Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) {
613 String expectedOperationId = operationEntry.getValue().getUniqueId();
614 if (expectedOperationId.equals(inputOperationId)) {
615 ListDataDefinition<OperationOutputDefinition> operationOutputs =
616 operationEntry.getValue().getOutputs();
617 return (Objects.isNull(operationOutputs) || operationOutputs.isEmpty())
618 ? operationOutputDefinitions
619 : operationOutputs.getListToscaDataDefinition();
623 return operationOutputDefinitions;
626 private boolean isValidOperationType(String operationType) {
627 return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);