2 * Copyright © 2016-2018 European Support Limited
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.openecomp.sdc.be.components.validation;
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;
39 import java.util.regex.Pattern;
40 import java.util.stream.Collectors;
42 @Component("interfaceOperationValidation")
43 public class InterfaceOperationValidation {
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;
50 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
52 public Either<Boolean, ResponseFormat> validateInterfaceOperations(
53 Collection<Operation> interfaceOperations,
54 String resourceId, boolean isUpdate) {
56 for(Operation interfaceOperation : interfaceOperations) {
57 Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
58 interfaceOperation, resourceId, isUpdate);
59 if (interfaceOperationValidatorResponse.isRight()) {
60 return interfaceOperationValidatorResponse;
63 return Either.left(Boolean.TRUE);
66 private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
67 String resourceId, boolean isUpdate) {
68 ResponseFormatManager responseFormatManager = getResponseFormatManager();
70 Either<Boolean, ResponseFormat> interfaceOperationTypeResponse = isInterfaceOperationTypeValid(interfaceOperation,
71 responseFormatManager, resourceId, isUpdate);
72 if (interfaceOperationTypeResponse.isRight()) {
73 return Either.right(interfaceOperationTypeResponse.right().value());
76 Either<Boolean, ResponseFormat> descriptionResponseEither = isValidDescription(responseFormatManager,
77 interfaceOperation.getDescription());
78 if (descriptionResponseEither.isRight()) {
79 return Either.right(descriptionResponseEither.right().value());
82 Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation,
83 responseFormatManager);
84 if(inputParametersResponse.isRight()) {
85 return Either.right(inputParametersResponse.right().value());
88 Either<Boolean, ResponseFormat> outputParametersResponse = validateOutputParameters(interfaceOperation,
89 responseFormatManager);
90 if(outputParametersResponse.isRight()) {
91 return Either.right(outputParametersResponse.right().value());
94 return Either.left(Boolean.TRUE);
97 private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
98 ResponseFormatManager responseFormatManager,
99 String resourceId, boolean isUpdate) {
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());
107 Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
108 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
109 if (operationTypeRegexValidationResponse.isRight()) {
110 return Either.right(operationTypeRegexValidationResponse.right().value());
113 Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
114 resourceId, isUpdate, responseFormatManager );
115 if(operationTypeUniqueResponse.isRight()) {
116 return Either.right(operationTypeUniqueResponse.right().value());
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);
124 return Either.left(Boolean.TRUE);
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);
136 return Either.left(Boolean.TRUE);
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);
147 return Either.left(Boolean.TRUE);
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);
158 return Either.left(Boolean.TRUE);
161 private boolean isValidOperationType(String operationType) {
162 return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
165 private Either<Boolean, ResponseFormat> validateOperationTypeUnique(
166 Operation interfaceOperation,
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));
180 Collection<InterfaceDefinition> interfaceDefinitions = interfaceOperationOrigin.left().value()
181 .getInterfaces().values();
182 if(CollectionUtils.isEmpty(interfaceDefinitions)){
183 isOperationTypeUnique = true;
184 return Either.left(isOperationTypeUnique);
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);
195 Map<String, String> operationTypes = new HashMap<>();
196 allOperations.forEach(operationType -> operationTypes.put(operationType.getUniqueId(),
197 operationType.getName()) );
200 isOperationTypeUnique = validateOperationTypeUniqueForUpdate(interfaceOperation, operationTypes);
203 if (!operationTypes.values().contains(interfaceOperation.getName())){
204 isOperationTypeUnique = true;
206 return Either.left(isOperationTypeUnique);
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);
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);
225 return Either.left(Boolean.TRUE);
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);
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);
246 return Either.left(Boolean.TRUE);
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());
259 if(!duplicateParamNamesToReturn.isEmpty()) {
260 return Either.right(duplicateParamNamesToReturn);
262 return Either.left(Boolean.TRUE);
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());
274 if(!duplicateParamNamesToReturn.isEmpty()) {
275 return Either.right(duplicateParamNamesToReturn);
277 return Either.left(Boolean.TRUE);
280 private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
281 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
282 .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
284 private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
285 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
286 .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
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;
298 if(entry.getKey().equals(interfaceOperation.getUniqueId()) && !operationTypes.values()
299 .contains(interfaceOperation.getName())){
300 isOperationTypeUnique = true;
303 return isOperationTypeUnique;
306 protected ResponseFormatManager getResponseFormatManager() {
307 return ResponseFormatManager.getInstance();