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