bfb2429a83352b59a1e89072350330240d369018
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / validation / InterfaceOperationValidation.java
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 fj.data.Either;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Objects;
26 import java.util.Optional;
27 import java.util.Set;
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;
42
43 @Component("interfaceOperationValidation")
44 public class InterfaceOperationValidation {
45
46     private static final String TYPE_VALIDATION_REGEX = "^[a-zA-Z]{1,200}$";
47
48     private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
49
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) {
53
54         Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType =
55             validateAllowedOperationCountOnLocalInterfaceType(inputInterfaceDefinition, storedInterfaceDefinition, globalInterfaceTypes, isUpdate);
56         if(validateAllowedOperationCountOnLocalInterfaceType.isRight()){
57             return validateAllowedOperationCountOnLocalInterfaceType;
58         }
59
60         Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType = validateAllowedOperationsOnGlobalInterfaceType(inputInterfaceDefinition, globalInterfaceTypes);
61         if(validateAllowedOperationsOnGlobalInterfaceType.isRight()){
62             return validateAllowedOperationsOnGlobalInterfaceType;
63         }
64
65         Either<Boolean, ResponseFormat> validateOperationNameUniqueness = validateOperationNameUniquenessInCollection(inputInterfaceDefinition.getOperationsMap().values());
66         if(validateOperationNameUniqueness.isRight()){
67             return validateOperationNameUniqueness;
68         }
69
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;
75             }
76         }
77
78         return Either.left(Boolean.TRUE);
79     }
80
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()));
86             }
87         }
88         return Either.left(Boolean.TRUE);
89     }
90
91     private Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType(InterfaceDefinition inputInterfaceDefinition,
92         InterfaceDefinition storedInterfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate){
93
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()));
98         }
99
100         return Either.left(Boolean.TRUE);
101     }
102
103     private Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType(InterfaceDefinition interfaceDefinition,
104         Map<String, InterfaceDefinition> globalInterfaceTypes) {
105
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()));
115             }
116         }
117         return Either.left(Boolean.TRUE);
118     }
119
120     private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
121         InterfaceDefinition interfaceDefinition,
122         org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
123
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());
129         }
130
131         if(null != interfaceOperation.getInputs()) {
132             Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation, responseFormatManager);
133             if (inputParametersResponse.isRight()) {
134                 return Either.right(inputParametersResponse.right().value());
135             }
136
137             Either<Boolean, ResponseFormat> inputPropertyExistInComponent = validateInputPropertyExistInComponent(interfaceOperation,
138                 component, responseFormatManager);
139             if(inputPropertyExistInComponent.isRight()) {
140                 return Either.right(inputPropertyExistInComponent.right().value());
141
142             }
143         }
144
145         if(null != interfaceOperation.getOutputs()) {
146             Either<Boolean, ResponseFormat> outputParametersResponse = validateOutputParameters(interfaceOperation, responseFormatManager);
147             if (outputParametersResponse.isRight()) {
148                 return Either.right(outputParametersResponse.right().value());
149             }
150         }
151
152         return Either.left(Boolean.TRUE);
153     }
154
155     private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
156         ResponseFormatManager responseFormatManager, InterfaceDefinition interfaceDefinition,
157         boolean isUpdate) {
158
159         Either<Boolean, ResponseFormat> operationTypeEmptyEither =
160             isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName());
161         if (operationTypeEmptyEither.isRight()) {
162             return Either.right(operationTypeEmptyEither.right().value());
163         }
164
165         Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
166             isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
167         if (operationTypeRegexValidationResponse.isRight()) {
168             return Either.right(operationTypeRegexValidationResponse.right().value());
169         }
170
171         Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
172             interfaceDefinition, isUpdate );
173         if(operationTypeUniqueResponse.isRight()) {
174             return Either.right(operationTypeUniqueResponse.right().value());
175         }
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);
181         }
182         return Either.left(Boolean.TRUE);
183     }
184
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);
193         }
194         return Either.left(Boolean.TRUE);
195     }
196
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);
204         }
205         return Either.left(Boolean.TRUE);
206     }
207
208     private boolean isValidOperationType(String operationType) {
209         return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
210     }
211
212     private Either<Boolean, ResponseFormat> validateOperationTypeUnique(
213         Operation interfaceOperation, InterfaceDefinition interfaceDefinition,
214         boolean isUpdate) {
215         boolean isOperationTypeUnique = false;
216
217         if(interfaceDefinition == null || CollectionUtils.isEmpty(interfaceDefinition.getOperationsMap().values())){
218             return Either.left(true);
219         }
220
221         Map<String, String> operationTypes = new HashMap<>();
222         interfaceDefinition.getOperationsMap().values().forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()));
223
224         if (!operationTypes.values().contains(interfaceOperation.getName())){
225             isOperationTypeUnique = true;
226         }
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;
232             }
233         }
234
235         return Either.left(isOperationTypeUnique);
236     }
237
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);
244         }
245
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);
253         }
254         return Either.left(Boolean.TRUE);
255     }
256
257
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);
264         }
265
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);
273         }
274         return Either.left(Boolean.TRUE);
275     }
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());
283                 }
284             });
285         if(!duplicateParamNamesToReturn.isEmpty()) {
286             return Either.right(duplicateParamNamesToReturn);
287         }
288         return Either.left(Boolean.TRUE);
289     }
290
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());
298                 }
299             });
300         if(!duplicateParamNamesToReturn.isEmpty()) {
301             return Either.right(duplicateParamNamesToReturn);
302         }
303         return Either.left(Boolean.TRUE);
304     }
305
306     private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
307         return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
308             .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
309     }
310     private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
311         return operationDataDefinition.getOutputs().getListToscaDataDefinition().stream()
312             .anyMatch(outputParam -> outputParam.getName() == null || outputParam.getName().trim().equals(StringUtils.EMPTY));
313     }
314
315     private  Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation,
316         org.openecomp.sdc.be.model.Component component,
317         ResponseFormatManager responseFormatManager) {
318
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);
326             }
327         }
328         return Either.left(Boolean.TRUE);
329     }
330
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('.'))))) ;
337     }
338
339     protected ResponseFormatManager getResponseFormatManager() {
340         return ResponseFormatManager.getInstance();
341     }
342
343 }