affafaed12dcecd63816fd3c0bb2c049e5afd5e7
[sdc.git] /
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.Map;
24 import java.util.Objects;
25 import java.util.Optional;
26 import java.util.Set;
27 import java.util.regex.Pattern;
28 import java.util.stream.Collectors;
29 import org.apache.commons.collections.CollectionUtils;
30 import org.apache.commons.collections.MapUtils;
31 import org.apache.commons.lang.StringUtils;
32 import org.elasticsearch.common.Strings;
33 import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
34 import org.openecomp.sdc.be.dao.api.ActionStatus;
35 import org.openecomp.sdc.be.model.InterfaceDefinition;
36 import org.openecomp.sdc.be.model.Operation;
37 import org.openecomp.sdc.be.model.Resource;
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     private static final int DESCRIPTION_MAX_LENGTH = 200;
48
49     private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
50
51     public Either<Boolean, ResponseFormat> validateInterfaceOperations(
52         Collection<Operation> interfaceOperations, org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
53
54         for(Operation interfaceOperation : interfaceOperations) {
55             Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
56                 interfaceOperation, component, isUpdate);
57             if (interfaceOperationValidatorResponse.isRight()) {
58                 return interfaceOperationValidatorResponse;
59             }
60         }
61         return Either.left(Boolean.TRUE);
62     }
63
64     private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
65         org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
66         ResponseFormatManager responseFormatManager = getResponseFormatManager();
67
68         Either<Boolean, ResponseFormat> interfaceOperationTypeResponse = isInterfaceOperationTypeValid(interfaceOperation,
69             responseFormatManager, component, isUpdate);
70         if (interfaceOperationTypeResponse.isRight()) {
71             return Either.right(interfaceOperationTypeResponse.right().value());
72         }
73
74         Either<Boolean, ResponseFormat> descriptionResponseEither = isValidDescription(responseFormatManager,
75             interfaceOperation.getDescription());
76         if (descriptionResponseEither.isRight()) {
77             return Either.right(descriptionResponseEither.right().value());
78         }
79
80         Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation,
81             responseFormatManager);
82         if(inputParametersResponse.isRight()) {
83             return Either.right(inputParametersResponse.right().value());
84         }
85
86         Either<Boolean, ResponseFormat> outputParametersResponse = validateOutputParameters(interfaceOperation,
87             responseFormatManager);
88         if(outputParametersResponse.isRight()) {
89             return Either.right(outputParametersResponse.right().value());
90         }
91
92         return Either.left(Boolean.TRUE);
93     }
94
95     private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
96         ResponseFormatManager responseFormatManager,
97         org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
98
99         Either<Boolean, ResponseFormat> operationTypeEmptyEither =
100             isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName());
101         if (operationTypeEmptyEither.isRight()) {
102             return Either.right(operationTypeEmptyEither.right().value());
103         }
104
105         Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
106             isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
107         if (operationTypeRegexValidationResponse.isRight()) {
108             return Either.right(operationTypeRegexValidationResponse.right().value());
109         }
110
111         Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
112             component, isUpdate, responseFormatManager );
113         if(operationTypeUniqueResponse.isRight()) {
114             return Either.right(operationTypeUniqueResponse.right().value());
115         }
116         if (!operationTypeUniqueResponse.left().value()) {
117             LOGGER.error("Interface Operation type  {} already in use ", interfaceOperation.getName());
118             ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
119                 .INTERFACE_OPERATION_TYPE_ALREADY_IN_USE, interfaceOperation.getName());
120             return Either.right(errorResponse);
121         }
122         return Either.left(Boolean.TRUE);
123     }
124
125     private Either<Boolean, ResponseFormat> isOperationTypeRegexValid(ResponseFormatManager responseFormatManager,
126         String operationType) {
127         if (!isValidOperationType(operationType)) {
128             LOGGER.error("Interface Operation type {} is invalid, Operation type should not contain" +
129                 "Special character, space, numbers and  should not be greater than 200 characters", operationType);
130             ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
131                 .INTERFACE_OPERATION_TYPE_INVALID, operationType);
132             return Either.right(errorResponse);
133         }
134         return Either.left(Boolean.TRUE);
135     }
136
137     private Either<Boolean, ResponseFormat> isOperationTypeEmpty(ResponseFormatManager responseFormatManager,
138         String operationType) {
139         if (StringUtils.isEmpty(operationType)) {
140             LOGGER.error("Interface Operation type is mandatory");
141             ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
142                 .INTERFACE_OPERATION_TYPE_MANDATORY);
143             return Either.right(errorResponse);
144         }
145         return Either.left(Boolean.TRUE);
146     }
147
148     private Either<Boolean, ResponseFormat> isValidDescription(ResponseFormatManager responseFormatManager,
149         String description) {
150         if (!Strings.isNullOrEmpty(description) && description.length() > DESCRIPTION_MAX_LENGTH) {
151             LOGGER.error("Interface Operation description {} is invalid, maximum 200 characters allowed", description);
152             ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus
153                 .INTERFACE_OPERATION_DESCRIPTION_MAX_LENGTH);
154             return Either.right(errorResponse);
155         }
156         return Either.left(Boolean.TRUE);
157     }
158
159     private boolean isValidOperationType(String operationType) {
160         return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
161     }
162
163     private Either<Boolean, ResponseFormat> validateOperationTypeUnique(
164         Operation interfaceOperation,
165         org.openecomp.sdc.be.model.Component component,
166         boolean isUpdate,
167         ResponseFormatManager responseFormatManager) {
168         boolean isOperationTypeUnique = false;
169
170         Map<String, InterfaceDefinition> interfaceDefinitionMap = ((Resource)component).getInterfaces();
171         if(interfaceDefinitionMap.isEmpty()){
172             isOperationTypeUnique = true;
173             return Either.left(isOperationTypeUnique);
174         }
175
176         Collection<Operation> allOperations = interfaceDefinitionMap.values().stream()
177             .filter(a -> MapUtils.isNotEmpty(a.getOperationsMap()))
178             .map(a -> a.getOperationsMap().values()).flatMap(Collection::stream)
179             .collect(Collectors.toList());
180         if(CollectionUtils.isEmpty(allOperations)){
181             isOperationTypeUnique = true;
182             return Either.left(isOperationTypeUnique);
183         }
184
185         Map<String, String> operationTypes = new HashMap<>();
186         allOperations.forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()));
187
188         if (!operationTypes.values().contains(interfaceOperation.getName())){
189             isOperationTypeUnique = true;
190         }
191         if (!isOperationTypeUnique && isUpdate){
192             Optional<String> id = operationTypes.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(), interfaceOperation.getName()))
193                 .map(Map.Entry::getKey).findAny();
194             if(id.isPresent() && id.get().equalsIgnoreCase(interfaceOperation.getUniqueId())){
195                 isOperationTypeUnique = true;
196             }
197         }
198
199         return Either.left(isOperationTypeUnique);
200     }
201     private Either<Boolean, ResponseFormat> validateInputParameters(Operation interfaceOperation,
202         ResponseFormatManager responseFormatManager) {
203         if (isInputParameterNameEmpty(interfaceOperation)) {
204             LOGGER.error("Interface operation input parameter name can't be empty");
205             ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_MANDATORY);
206             return Either.right(inputResponse);
207         }
208
209         Either<Boolean, Set<String>> validateInputParametersUniqueResponse = isInputParametersUnique(interfaceOperation);
210         if(validateInputParametersUniqueResponse.isRight()) {
211             LOGGER.error("Interface operation input parameter names {} already in use",
212                 validateInputParametersUniqueResponse.right().value());
213             ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus
214                 .INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE, validateInputParametersUniqueResponse.right().value().toString());
215             return Either.right(inputResponse);
216         }
217         return Either.left(Boolean.TRUE);
218     }
219
220
221     private Either<Boolean, ResponseFormat> validateOutputParameters(Operation interfaceOperation,
222         ResponseFormatManager responseFormatManager) {
223         if (isOutputParameterNameEmpty(interfaceOperation)) {
224             LOGGER.error("Interface operation output parameter name can't be empty");
225             ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY);
226             return Either.right(inputResponse);
227         }
228
229         Either<Boolean, Set<String>> validateOutputParametersUniqueResponse = isOutputParametersUnique(interfaceOperation);
230         if(validateOutputParametersUniqueResponse.isRight()) {
231             LOGGER.error("Interface operation output parameter names {} already in use",
232                 validateOutputParametersUniqueResponse.right().value());
233             ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus
234                 .INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE, validateOutputParametersUniqueResponse.right().value().toString());
235             return Either.right(inputResponse);
236         }
237         return Either.left(Boolean.TRUE);
238     }
239
240
241     private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) {
242         Set<String> inputParamNamesSet = new HashSet<>();
243         Set<String> duplicateParamNamesToReturn = new HashSet<>();
244         operationDataDefinition.getInputs().getListToscaDataDefinition()
245             .forEach(inputParam -> {
246                 if(!inputParamNamesSet.add(inputParam.getName().trim())) {
247                     duplicateParamNamesToReturn.add(inputParam.getName().trim());
248                 }
249             });
250         if(!duplicateParamNamesToReturn.isEmpty()) {
251             return Either.right(duplicateParamNamesToReturn);
252         }
253         return Either.left(Boolean.TRUE);
254     }
255
256     private Either<Boolean, Set<String>> isOutputParametersUnique(Operation operationDataDefinition) {
257         Set<String> outputParamNamesSet = new HashSet<>();
258         Set<String> duplicateParamNamesToReturn = new HashSet<>();
259         operationDataDefinition.getOutputs().getListToscaDataDefinition()
260             .forEach(outputParam -> {
261                 if(!outputParamNamesSet.add(outputParam.getName().trim())) {
262                     duplicateParamNamesToReturn.add(outputParam.getName().trim());
263                 }
264             });
265         if(!duplicateParamNamesToReturn.isEmpty()) {
266             return Either.right(duplicateParamNamesToReturn);
267         }
268         return Either.left(Boolean.TRUE);
269     }
270
271     private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
272         return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
273             .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
274     }
275     private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
276         return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
277             .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
278     }
279
280     private boolean validateOperationTypeUniqueForUpdate(Operation interfaceOperation, Map<String, String> operationTypes) {
281         boolean isOperationTypeUnique = false;
282         Optional<String> id = operationTypes.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(), interfaceOperation.getName()))
283             .map(Map.Entry::getKey).findAny();
284         if(id.isPresent() && id.get().equalsIgnoreCase(interfaceOperation.getUniqueId())){
285             isOperationTypeUnique = true;
286         }
287         return isOperationTypeUnique;
288     }
289
290     protected ResponseFormatManager getResponseFormatManager() {
291         return ResponseFormatManager.getInstance();
292     }
293
294 }