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