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 org.apache.commons.collections.CollectionUtils;
21 import org.apache.commons.collections.MapUtils;
22 import org.apache.commons.lang.StringUtils;
23 import org.elasticsearch.common.Strings;
24 import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
25 import org.openecomp.sdc.be.dao.api.ActionStatus;
26 import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
27 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
28 import org.openecomp.sdc.be.model.InputDefinition;
29 import org.openecomp.sdc.be.model.InterfaceDefinition;
30 import org.openecomp.sdc.be.model.Operation;
31 import org.openecomp.sdc.exception.ResponseFormat;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.springframework.stereotype.Component;
36 import java.util.Collection;
37 import java.util.HashMap;
38 import java.util.HashSet;
39 import java.util.List;
41 import java.util.Objects;
42 import java.util.Optional;
44 import java.util.regex.Pattern;
45 import java.util.stream.Collectors;
47 @Component("interfaceOperationValidation")
48 public class InterfaceOperationValidation {
50 private static final String TYPE_VALIDATION_REGEX = "^[a-zA-Z]{1,200}$";
51 private static final int DESCRIPTION_MAX_LENGTH = 200;
53 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
55 public Either<Boolean, ResponseFormat> validateInterfaceOperations(
56 Collection<Operation> interfaceOperations, org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
58 for(Operation interfaceOperation : interfaceOperations) {
59 Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
60 interfaceOperation, component, isUpdate);
61 if (interfaceOperationValidatorResponse.isRight()) {
62 return interfaceOperationValidatorResponse;
65 return Either.left(Boolean.TRUE);
68 private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
69 org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
70 ResponseFormatManager responseFormatManager = getResponseFormatManager();
72 Either<Boolean, ResponseFormat> interfaceOperationTypeResponse = isInterfaceOperationTypeValid(interfaceOperation,
73 responseFormatManager, component, isUpdate);
74 if (interfaceOperationTypeResponse.isRight()) {
75 return Either.right(interfaceOperationTypeResponse.right().value());
78 Either<Boolean, ResponseFormat> descriptionResponseEither = isValidDescription(responseFormatManager,
79 interfaceOperation.getDescription());
80 if (descriptionResponseEither.isRight()) {
81 return Either.right(descriptionResponseEither.right().value());
84 Either<Boolean, ResponseFormat> inputPropertyExistInComponent = validateInputPropertyExistInComponent(interfaceOperation,
85 component.getInputs(), responseFormatManager);
86 if(inputPropertyExistInComponent.isRight()) {
87 return Either.right(inputPropertyExistInComponent.right().value());
91 Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation,
92 responseFormatManager);
93 if(inputParametersResponse.isRight()) {
94 return Either.right(inputParametersResponse.right().value());
97 Either<Boolean, ResponseFormat> outputParametersResponse = validateOutputParameters(interfaceOperation,
98 responseFormatManager);
99 if(outputParametersResponse.isRight()) {
100 return Either.right(outputParametersResponse.right().value());
103 return Either.left(Boolean.TRUE);
106 private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
107 ResponseFormatManager responseFormatManager,
108 org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
110 Either<Boolean, ResponseFormat> operationTypeEmptyEither =
111 isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName());
112 if (operationTypeEmptyEither.isRight()) {
113 return Either.right(operationTypeEmptyEither.right().value());
116 Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
117 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
118 if (operationTypeRegexValidationResponse.isRight()) {
119 return Either.right(operationTypeRegexValidationResponse.right().value());
122 Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
123 component, isUpdate );
124 if(operationTypeUniqueResponse.isRight()) {
125 return Either.right(operationTypeUniqueResponse.right().value());
127 if (!operationTypeUniqueResponse.left().value()) {
128 LOGGER.error("Interface Operation type {} already in use ", interfaceOperation.getName());
129 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
130 .INTERFACE_OPERATION_NAME_ALREADY_IN_USE, interfaceOperation.getName());
131 return Either.right(errorResponse);
133 return Either.left(Boolean.TRUE);
136 private Either<Boolean, ResponseFormat> isOperationTypeRegexValid(ResponseFormatManager responseFormatManager,
137 String operationType) {
138 if (!isValidOperationType(operationType)) {
139 LOGGER.error("Interface Operation type {} is invalid, Operation type should not contain" +
140 "Special character, space, numbers and should not be greater than 200 characters", operationType);
141 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
142 .INTERFACE_OPERATION_NAME_INVALID, operationType);
143 return Either.right(errorResponse);
145 return Either.left(Boolean.TRUE);
148 private Either<Boolean, ResponseFormat> isOperationTypeEmpty(ResponseFormatManager responseFormatManager,
149 String operationType) {
150 if (StringUtils.isEmpty(operationType)) {
151 LOGGER.error("Interface Operation type is mandatory");
152 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
153 .INTERFACE_OPERATION_NAME_MANDATORY);
154 return Either.right(errorResponse);
156 return Either.left(Boolean.TRUE);
159 private Either<Boolean, ResponseFormat> isValidDescription(ResponseFormatManager responseFormatManager,
160 String description) {
161 if (!Strings.isNullOrEmpty(description) && description.length() > DESCRIPTION_MAX_LENGTH) {
162 LOGGER.error("Interface Operation description {} is invalid, maximum 200 characters allowed", description);
163 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
164 .INTERFACE_OPERATION_DESCRIPTION_MAX_LENGTH, description);
165 return Either.right(errorResponse);
167 return Either.left(Boolean.TRUE);
170 private boolean isValidOperationType(String operationType) {
171 return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
174 private Either<Boolean, ResponseFormat> validateOperationTypeUnique(
175 Operation interfaceOperation,
176 org.openecomp.sdc.be.model.Component component,
178 boolean isOperationTypeUnique = false;
180 Map<String, InterfaceDefinition> interfaceDefinitionMap = component.getInterfaces();
181 if(interfaceDefinitionMap.isEmpty()){
182 return Either.left(true);
185 Collection<Operation> allOperations = interfaceDefinitionMap.values().stream()
186 .filter(a -> MapUtils.isNotEmpty(a.getOperationsMap()))
187 .map(a -> a.getOperationsMap().values()).flatMap(Collection::stream)
188 .collect(Collectors.toList());
189 if(CollectionUtils.isEmpty(allOperations)){
190 return Either.left(true);
193 Map<String, String> operationTypes = new HashMap<>();
194 allOperations.forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()));
196 if (!operationTypes.values().contains(interfaceOperation.getName())){
197 isOperationTypeUnique = true;
199 if (!isOperationTypeUnique && isUpdate){
200 Optional<String> id = operationTypes.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(), interfaceOperation.getName()))
201 .map(Map.Entry::getKey).findAny();
202 if(id.isPresent() && id.get().equalsIgnoreCase(interfaceOperation.getUniqueId())){
203 isOperationTypeUnique = true;
207 return Either.left(isOperationTypeUnique);
209 private Either<Boolean, ResponseFormat> validateInputParameters(Operation interfaceOperation,
210 ResponseFormatManager responseFormatManager) {
211 if (isInputParameterNameEmpty(interfaceOperation)) {
212 LOGGER.error("Interface operation input parameter name can't be empty");
213 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_MANDATORY);
214 return Either.right(inputResponse);
217 Either<Boolean, Set<String>> validateInputParametersUniqueResponse = isInputParametersUnique(interfaceOperation);
218 if(validateInputParametersUniqueResponse.isRight()) {
219 LOGGER.error("Interface operation input parameter names {} already in use",
220 validateInputParametersUniqueResponse.right().value());
221 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus
222 .INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE, validateInputParametersUniqueResponse.right().value().toString());
223 return Either.right(inputResponse);
225 return Either.left(Boolean.TRUE);
229 private Either<Boolean, ResponseFormat> validateOutputParameters(Operation interfaceOperation,
230 ResponseFormatManager responseFormatManager) {
231 if (isOutputParameterNameEmpty(interfaceOperation)) {
232 LOGGER.error("Interface operation output parameter name can't be empty");
233 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY);
234 return Either.right(inputResponse);
237 Either<Boolean, Set<String>> validateOutputParametersUniqueResponse = isOutputParametersUnique(interfaceOperation);
238 if(validateOutputParametersUniqueResponse.isRight()) {
239 LOGGER.error("Interface operation output parameter names {} already in use",
240 validateOutputParametersUniqueResponse.right().value());
241 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus
242 .INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE, validateOutputParametersUniqueResponse.right().value().toString());
243 return Either.right(inputResponse);
245 return Either.left(Boolean.TRUE);
247 private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) {
248 Set<String> inputParamNamesSet = new HashSet<>();
249 Set<String> duplicateParamNamesToReturn = new HashSet<>();
250 operationDataDefinition.getInputs().getListToscaDataDefinition()
251 .forEach(inputParam -> {
252 if(!inputParamNamesSet.add(inputParam.getName().trim())) {
253 duplicateParamNamesToReturn.add(inputParam.getName().trim());
256 if(!duplicateParamNamesToReturn.isEmpty()) {
257 return Either.right(duplicateParamNamesToReturn);
259 return Either.left(Boolean.TRUE);
262 private Either<Boolean, Set<String>> isOutputParametersUnique(Operation operationDataDefinition) {
263 Set<String> outputParamNamesSet = new HashSet<>();
264 Set<String> duplicateParamNamesToReturn = new HashSet<>();
265 operationDataDefinition.getOutputs().getListToscaDataDefinition()
266 .forEach(outputParam -> {
267 if(!outputParamNamesSet.add(outputParam.getName().trim())) {
268 duplicateParamNamesToReturn.add(outputParam.getName().trim());
271 if(!duplicateParamNamesToReturn.isEmpty()) {
272 return Either.right(duplicateParamNamesToReturn);
274 return Either.left(Boolean.TRUE);
277 private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
278 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
279 .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
281 private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
282 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
283 .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
286 private Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation,
287 List<InputDefinition> inputs,
288 ResponseFormatManager responseFormatManager) {
289 ListDataDefinition<OperationInputDefinition> inputDefinitionListDataDefinition = operation.getInputs();
290 if (inputDefinitionListDataDefinition == null) {
291 return Either.left(Boolean.TRUE);
293 List<OperationInputDefinition> inputListToscaDataDefinition = inputDefinitionListDataDefinition.getListToscaDataDefinition();
295 for(OperationInputDefinition inputDefinition : inputListToscaDataDefinition ) {
296 if(!validateInputExistsInComponent(inputDefinition, inputs)) {
297 String missingPropertyName = inputDefinition.getInputId().contains(".") ? inputDefinition.getInputId().substring(inputDefinition.getInputId().indexOf(".") + 1) : inputDefinition.getInputId();
298 LOGGER.error("Interface operation input property {} not found in component input properties", missingPropertyName);
299 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT, missingPropertyName);
300 return Either.right(inputResponse);
303 return Either.left(Boolean.TRUE);
306 private boolean validateInputExistsInComponent(OperationInputDefinition input,
307 List<InputDefinition> inputs) {
308 return inputs.stream().anyMatch(inp -> inp.getUniqueId().equals(input.getInputId()));
311 private ResponseFormatManager getResponseFormatManager() {
312 return ResponseFormatManager.getInstance();