/* * Copyright © 2016-2018 European Support Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.openecomp.sdc.be.components.validation; import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang.StringUtils; import org.openecomp.sdc.be.components.impl.ResponseFormatManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Operation; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; @Component("interfaceOperationValidation") public class InterfaceOperationValidation { @Autowired private ToscaOperationFacade toscaOperationFacade; private static final String TYPE_VALIDATION_REGEX = "^[a-zA-Z]{1,200}$"; private static final int DESCRIPTION_MAX_LENGTH = 200; private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class); public Either validateInterfaceOperations( Collection interfaceOperations, String resourceId, boolean isUpdate) { for(Operation interfaceOperation : interfaceOperations) { Either interfaceOperationValidatorResponse = validateInterfaceOperation( interfaceOperation, resourceId, isUpdate); if (interfaceOperationValidatorResponse.isRight()) { return interfaceOperationValidatorResponse; } } return Either.left(Boolean.TRUE); } private Either validateInterfaceOperation(Operation interfaceOperation, String resourceId, boolean isUpdate) { ResponseFormatManager responseFormatManager = getResponseFormatManager(); Either interfaceOperationTypeResponse = validateInterfaceOperationType(interfaceOperation, responseFormatManager, resourceId, isUpdate); if (interfaceOperationTypeResponse != null) { return interfaceOperationTypeResponse; } Either descriptionResponseEither = validateDescription(responseFormatManager, interfaceOperation.getDescription()); if (descriptionResponseEither != null) { return descriptionResponseEither; } Either inputParametersResponse = validateInputParameters(interfaceOperation, responseFormatManager); if(inputParametersResponse != null) { return inputParametersResponse; } return Either.left(true); } private Either validateInterfaceOperationType(Operation interfaceOperation, ResponseFormatManager responseFormatManager, String resourceId, boolean isUpdate) { Either operationTypeEmptyEither = isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName()); // treating name as type for now if (operationTypeEmptyEither != null) { return operationTypeEmptyEither; } Either operationTypeRegexValidationResponse = validateOperationTypeRegex(responseFormatManager, interfaceOperation.getName()); if (operationTypeRegexValidationResponse != null) { return operationTypeRegexValidationResponse; } Either operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation, resourceId, isUpdate, responseFormatManager ); if(operationTypeUniqueResponse.isRight()) { return Either.right(operationTypeUniqueResponse.right().value()); } if (!operationTypeUniqueResponse.left().value()) { LOGGER.debug("Interface Operation type {} already in use ", interfaceOperation.getName()); ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus .INTERFACE_OPERATION_TYPE_ALREADY_IN_USE, interfaceOperation.getName()); return Either.right(errorResponse); } return null; } private Either validateOperationTypeRegex(ResponseFormatManager responseFormatManager, String operationType) { if (!isValidOperationType(operationType)) { LOGGER.debug("Interface Operation type {} is invalid, Operation type should not contain" + "Special character, space and should not be greater than 200 characters", operationType); ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus .INTERFACE_OPERATION_TYPE_INVALID, operationType); return Either.right(errorResponse); } return null; } private Either isOperationTypeEmpty(ResponseFormatManager responseFormatManager, String operationType) { if (StringUtils.isEmpty(operationType)) { LOGGER.debug("Interface Operation type is mandatory, it can't be empty"); ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus .INTERFACE_OPERATION_TYPE_MANDATORY); return Either.right(errorResponse); } return null; } private Either validateDescription(ResponseFormatManager responseFormatManager, String description) { if (description.length() > DESCRIPTION_MAX_LENGTH) { LOGGER.debug("Interface Operation description {} is invalid, maximum 200 characters allowed", description); ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus .INTERFACE_OPERATION_DESCRIPTION_MAX_LENGTH); return Either.right(errorResponse); } return null; } private boolean isValidOperationType(String operationType) { return Pattern.matches(TYPE_VALIDATION_REGEX, operationType); } private Either validateOperationTypeUnique(Operation interfaceOperation, String resourceId, boolean isUpdate, ResponseFormatManager responseFormatManager) { boolean isOperationTypeUnique = false; ComponentParametersView filter = new ComponentParametersView(true); filter.setIgnoreInterfaces(false); Either interfaceOperationOrigin = toscaOperationFacade .getToscaElement(resourceId, filter); if (interfaceOperationOrigin.isRight()){ LOGGER.debug("Failed to fetch interface operation information by resource id {} ", resourceId); return Either.right(responseFormatManager.getResponseFormat(ActionStatus.GENERAL_ERROR)); } Collection interfaceDefinitions = interfaceOperationOrigin.left().value() .getInterfaces().values(); if(CollectionUtils.isEmpty(interfaceDefinitions)){ isOperationTypeUnique = true; return Either.left(isOperationTypeUnique); } Collection allOperations = interfaceDefinitions.stream() .filter(a -> MapUtils.isNotEmpty(a.getOperationsMap())) .map(a -> a.getOperationsMap().values()).flatMap(Collection::stream) .collect(Collectors.toList()); if(CollectionUtils.isEmpty(allOperations)){ isOperationTypeUnique = true; return Either.left(isOperationTypeUnique); } Map operationTypes = new HashMap<>(); allOperations.forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()) ); if (isUpdate){ isOperationTypeUnique = validateOperationTypeUniqueForUpdate(interfaceOperation, operationTypes); } else if (!operationTypes.values().contains(interfaceOperation.getName())){ isOperationTypeUnique = true; } return Either.left(isOperationTypeUnique); } private Either validateInputParameters(Operation interfaceOperation, ResponseFormatManager responseFormatManager) { Either> validateInputParametersUniqueResponse = validateInputParametersUnique(interfaceOperation); if(validateInputParametersUniqueResponse.isRight()) { LOGGER.debug("Interface operation input parameter names {} are invalid, Input parameter names should be unique", validateInputParametersUniqueResponse.right().value().toString()); ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus .INTERFACE_OPERATION_INPUT_NAME_INVALID, validateInputParametersUniqueResponse.right().value().toString()); return Either.right(inputResponse); } return null; } private Either> validateInputParametersUnique(Operation operationDataDefinition) { Set inputParamNamesSet = new HashSet<>(); Set duplicateParamNamesToReturn = new HashSet<>(); operationDataDefinition.getInputs().getListToscaDataDefinition() .forEach(inputParam -> { if(!inputParamNamesSet.add(inputParam.getLabel())) { duplicateParamNamesToReturn.add(inputParam.getLabel()); } }); if(!duplicateParamNamesToReturn.isEmpty()) { return Either.right(duplicateParamNamesToReturn); } return Either.left(Boolean.TRUE); } private boolean validateOperationTypeUniqueForUpdate(Operation interfaceOperation, Map operationTypes) { boolean isOperationTypeUnique = false; for(Map.Entry entry : operationTypes.entrySet()){ if (entry.getKey().equals(interfaceOperation.getUniqueId()) && entry.getValue(). equals(interfaceOperation.getName())) { isOperationTypeUnique = true; } if(entry.getKey().equals(interfaceOperation.getUniqueId()) && !operationTypes.values() .contains(interfaceOperation.getName())){ isOperationTypeUnique = true; } } return isOperationTypeUnique; } protected ResponseFormatManager getResponseFormatManager() { return ResponseFormatManager.getInstance(); } }