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