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 fj.data.Either;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
25 import java.util.Objects;
26 import java.util.Optional;
28 import java.util.regex.Pattern;
29 import java.util.stream.Stream;
30 import org.apache.commons.collections.CollectionUtils;
31 import org.apache.commons.lang.StringUtils;
32 import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
33 import org.openecomp.sdc.be.dao.api.ActionStatus;
34 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
35 import org.openecomp.sdc.be.model.InputDefinition;
36 import org.openecomp.sdc.be.model.InterfaceDefinition;
37 import org.openecomp.sdc.be.model.Operation;
38 import org.openecomp.sdc.exception.ResponseFormat;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.stereotype.Component;
43 @Component("interfaceOperationValidation")
44 public class InterfaceOperationValidation {
46 private static final String TYPE_VALIDATION_REGEX = "^[a-zA-Z]{1,200}$";
48 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
50 public Either<Boolean, ResponseFormat> validateInterfaceOperations(
51 InterfaceDefinition inputInterfaceDefinition, org.openecomp.sdc.be.model.Component component,
52 InterfaceDefinition storedInterfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate) {
54 Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType =
55 validateAllowedOperationCountOnLocalInterfaceType(inputInterfaceDefinition, storedInterfaceDefinition, globalInterfaceTypes, isUpdate);
56 if(validateAllowedOperationCountOnLocalInterfaceType.isRight()){
57 return validateAllowedOperationCountOnLocalInterfaceType;
60 Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType = validateAllowedOperationsOnGlobalInterfaceType(inputInterfaceDefinition, globalInterfaceTypes);
61 if(validateAllowedOperationsOnGlobalInterfaceType.isRight()){
62 return validateAllowedOperationsOnGlobalInterfaceType;
65 Either<Boolean, ResponseFormat> validateOperationNameUniqueness = validateOperationNameUniquenessInCollection(inputInterfaceDefinition.getOperationsMap().values());
66 if(validateOperationNameUniqueness.isRight()){
67 return validateOperationNameUniqueness;
70 for(Operation interfaceOperation : inputInterfaceDefinition.getOperationsMap().values()) {
71 Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
72 interfaceOperation, storedInterfaceDefinition, component, isUpdate);
73 if (interfaceOperationValidatorResponse.isRight()) {
74 return interfaceOperationValidatorResponse;
78 return Either.left(Boolean.TRUE);
81 private Either<Boolean, ResponseFormat> validateOperationNameUniquenessInCollection(Collection<Operation> operationList){
82 HashSet<String> operationNames = new HashSet<>();
83 for (Operation operation : operationList) {
84 if(!operationNames.add(operation.getName())){
85 return Either.right(getResponseFormatManager().getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE, operation.getName()));
88 return Either.left(Boolean.TRUE);
91 private Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType(InterfaceDefinition inputInterfaceDefinition,
92 InterfaceDefinition storedInterfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate){
94 boolean isInterfaceTypeExistInGlobalType = globalInterfaceTypes.values().stream().map(InterfaceDefinition::getType)
95 .anyMatch(type -> type.equalsIgnoreCase(inputInterfaceDefinition.getType()));
96 if(!isInterfaceTypeExistInGlobalType && (inputInterfaceDefinition.getOperations().size() > 1 || (!isUpdate && storedInterfaceDefinition != null && storedInterfaceDefinition.getType().equalsIgnoreCase(inputInterfaceDefinition.getType())))){
97 return Either.right(getResponseFormatManager().getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE, inputInterfaceDefinition.getType()));
100 return Either.left(Boolean.TRUE);
103 private Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType(InterfaceDefinition interfaceDefinition,
104 Map<String, InterfaceDefinition> globalInterfaceTypes) {
106 if(globalInterfaceTypes != null){
107 boolean isOperationValidOnGlobalInterfaceType = Stream.of(interfaceDefinition)
108 .filter(interfaceDef -> globalInterfaceTypes.values().stream().anyMatch(interfaceDef1 -> interfaceDef1.getType().equalsIgnoreCase(interfaceDef.getType())))
109 .flatMap(interfaceDef -> interfaceDef.getOperationsMap().values().stream().map(Operation::getName))
110 .allMatch(operationName -> globalInterfaceTypes.values().stream()
111 .flatMap(interfaceDef -> interfaceDef.getOperationsMap().keySet().stream().map(operation -> operation))
112 .anyMatch(opName -> opName.equalsIgnoreCase(operationName)));
113 if(!isOperationValidOnGlobalInterfaceType){
114 return Either.right(getResponseFormatManager().getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE, interfaceDefinition.getType()));
117 return Either.left(Boolean.TRUE);
120 private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
121 InterfaceDefinition interfaceDefinition,
122 org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
124 ResponseFormatManager responseFormatManager = getResponseFormatManager();
125 Either<Boolean, ResponseFormat> interfaceOperationTypeResponse = isInterfaceOperationTypeValid(interfaceOperation,
126 responseFormatManager, interfaceDefinition, isUpdate);
127 if (interfaceOperationTypeResponse.isRight()) {
128 return Either.right(interfaceOperationTypeResponse.right().value());
131 if(null != interfaceOperation.getInputs()) {
132 Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation, responseFormatManager);
133 if (inputParametersResponse.isRight()) {
134 return Either.right(inputParametersResponse.right().value());
137 Either<Boolean, ResponseFormat> inputPropertyExistInComponent = validateInputPropertyExistInComponent(interfaceOperation,
138 component, responseFormatManager);
139 if(inputPropertyExistInComponent.isRight()) {
140 return Either.right(inputPropertyExistInComponent.right().value());
145 if(null != interfaceOperation.getOutputs()) {
146 Either<Boolean, ResponseFormat> outputParametersResponse = validateOutputParameters(interfaceOperation, responseFormatManager);
147 if (outputParametersResponse.isRight()) {
148 return Either.right(outputParametersResponse.right().value());
152 return Either.left(Boolean.TRUE);
155 private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
156 ResponseFormatManager responseFormatManager, InterfaceDefinition interfaceDefinition,
159 Either<Boolean, ResponseFormat> operationTypeEmptyEither =
160 isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName());
161 if (operationTypeEmptyEither.isRight()) {
162 return Either.right(operationTypeEmptyEither.right().value());
165 Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
166 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
167 if (operationTypeRegexValidationResponse.isRight()) {
168 return Either.right(operationTypeRegexValidationResponse.right().value());
171 Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
172 interfaceDefinition, isUpdate );
173 if(operationTypeUniqueResponse.isRight()) {
174 return Either.right(operationTypeUniqueResponse.right().value());
176 if (!operationTypeUniqueResponse.left().value()) {
177 LOGGER.error("Interface Operation type {} already in use ", interfaceOperation.getName());
178 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
179 .INTERFACE_OPERATION_NAME_ALREADY_IN_USE, interfaceOperation.getName());
180 return Either.right(errorResponse);
182 return Either.left(Boolean.TRUE);
185 private Either<Boolean, ResponseFormat> isOperationTypeRegexValid(ResponseFormatManager responseFormatManager,
186 String operationType) {
187 if (!isValidOperationType(operationType)) {
188 LOGGER.error("Interface Operation type {} is invalid, Operation type should not contain" +
189 "Special character, space, numbers and should not be greater than 200 characters", operationType);
190 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
191 .INTERFACE_OPERATION_NAME_INVALID, operationType);
192 return Either.right(errorResponse);
194 return Either.left(Boolean.TRUE);
197 private Either<Boolean, ResponseFormat> isOperationTypeEmpty(ResponseFormatManager responseFormatManager,
198 String operationType) {
199 if (StringUtils.isEmpty(operationType)) {
200 LOGGER.error("Interface Operation type is mandatory");
201 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
202 .INTERFACE_OPERATION_NAME_MANDATORY);
203 return Either.right(errorResponse);
205 return Either.left(Boolean.TRUE);
208 private boolean isValidOperationType(String operationType) {
209 return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
212 private Either<Boolean, ResponseFormat> validateOperationTypeUnique(
213 Operation interfaceOperation, InterfaceDefinition interfaceDefinition,
215 boolean isOperationTypeUnique = false;
217 if(interfaceDefinition == null || CollectionUtils.isEmpty(interfaceDefinition.getOperationsMap().values())){
218 return Either.left(true);
221 Map<String, String> operationTypes = new HashMap<>();
222 interfaceDefinition.getOperationsMap().values().forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()));
224 if (!operationTypes.values().contains(interfaceOperation.getName())){
225 isOperationTypeUnique = true;
227 if (!isOperationTypeUnique && isUpdate){
228 Optional<String> id = operationTypes.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(), interfaceOperation.getName()))
229 .map(Map.Entry::getKey).findAny();
230 if(id.isPresent() && id.get().equalsIgnoreCase(interfaceOperation.getUniqueId())){
231 isOperationTypeUnique = true;
235 return Either.left(isOperationTypeUnique);
238 private Either<Boolean, ResponseFormat> validateInputParameters(Operation interfaceOperation,
239 ResponseFormatManager responseFormatManager) {
240 if (isInputParameterNameEmpty(interfaceOperation)) {
241 LOGGER.error("Interface operation input parameter name can't be empty");
242 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_MANDATORY);
243 return Either.right(inputResponse);
246 Either<Boolean, Set<String>> validateInputParametersUniqueResponse = isInputParametersUnique(interfaceOperation);
247 if(validateInputParametersUniqueResponse.isRight()) {
248 LOGGER.error("Interface operation input parameter names {} already in use",
249 validateInputParametersUniqueResponse.right().value());
250 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus
251 .INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE, validateInputParametersUniqueResponse.right().value().toString());
252 return Either.right(inputResponse);
254 return Either.left(Boolean.TRUE);
258 private Either<Boolean, ResponseFormat> validateOutputParameters(Operation interfaceOperation,
259 ResponseFormatManager responseFormatManager) {
260 if (isOutputParameterNameEmpty(interfaceOperation)) {
261 LOGGER.error("Interface operation output parameter name can't be empty");
262 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY);
263 return Either.right(inputResponse);
266 Either<Boolean, Set<String>> validateOutputParametersUniqueResponse = isOutputParametersUnique(interfaceOperation);
267 if(validateOutputParametersUniqueResponse.isRight()) {
268 LOGGER.error("Interface operation output parameter names {} already in use",
269 validateOutputParametersUniqueResponse.right().value());
270 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus
271 .INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE, validateOutputParametersUniqueResponse.right().value().toString());
272 return Either.right(inputResponse);
274 return Either.left(Boolean.TRUE);
276 private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) {
277 Set<String> inputParamNamesSet = new HashSet<>();
278 Set<String> duplicateParamNamesToReturn = new HashSet<>();
279 operationDataDefinition.getInputs().getListToscaDataDefinition()
280 .forEach(inputParam -> {
281 if(!inputParamNamesSet.add(inputParam.getName().trim())) {
282 duplicateParamNamesToReturn.add(inputParam.getName().trim());
285 if(!duplicateParamNamesToReturn.isEmpty()) {
286 return Either.right(duplicateParamNamesToReturn);
288 return Either.left(Boolean.TRUE);
291 private Either<Boolean, Set<String>> isOutputParametersUnique(Operation operationDataDefinition) {
292 Set<String> outputParamNamesSet = new HashSet<>();
293 Set<String> duplicateParamNamesToReturn = new HashSet<>();
294 operationDataDefinition.getOutputs().getListToscaDataDefinition()
295 .forEach(outputParam -> {
296 if(!outputParamNamesSet.add(outputParam.getName().trim())) {
297 duplicateParamNamesToReturn.add(outputParam.getName().trim());
300 if(!duplicateParamNamesToReturn.isEmpty()) {
301 return Either.right(duplicateParamNamesToReturn);
303 return Either.left(Boolean.TRUE);
306 private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
307 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
308 .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
310 private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
311 return operationDataDefinition.getOutputs().getListToscaDataDefinition().stream()
312 .anyMatch(outputParam -> outputParam.getName() == null || outputParam.getName().trim().equals(StringUtils.EMPTY));
315 private Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation,
316 org.openecomp.sdc.be.model.Component component,
317 ResponseFormatManager responseFormatManager) {
319 List<OperationInputDefinition> inputListToscaDataDefinition = operation.getInputs().getListToscaDataDefinition();
320 for(OperationInputDefinition inputDefinition : inputListToscaDataDefinition ) {
321 if(!validateInputExistsInComponent(inputDefinition, component.getInputs())) {
322 String missingPropertyName = inputDefinition.getInputId().contains(".") ? inputDefinition.getInputId().substring(inputDefinition.getInputId().indexOf('.') + 1) : inputDefinition.getInputId();
323 LOGGER.error("Interface operation input property {} not found in component input properties", missingPropertyName);
324 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT, missingPropertyName, component.getComponentType().getValue());
325 return Either.right(inputResponse);
328 return Either.left(Boolean.TRUE);
331 private boolean validateInputExistsInComponent(OperationInputDefinition input,
332 List<InputDefinition> inputs) {
333 return inputs.stream().anyMatch(inp -> inp.getUniqueId().equals(input.getInputId()))
334 || (input.getInputId().contains(".")
335 && inputs.stream().anyMatch(inp -> inp.getUniqueId().equals(
336 input.getInputId().substring(0, input.getInputId().lastIndexOf('.'))))) ;
339 protected ResponseFormatManager getResponseFormatManager() {
340 return ResponseFormatManager.getInstance();