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