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 java.util.Collection;
20 import java.util.HashMap;
21 import java.util.HashSet;
24 import java.util.regex.Pattern;
25 import java.util.stream.Collectors;
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;
45 import fj.data.Either;
47 @Component("interfaceOperationValidation")
48 public class InterfaceOperationValidation {
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;
55 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
57 public Either<Boolean, ResponseFormat> validateInterfaceOperations(
58 Collection<Operation> interfaceOperations,
59 String resourceId, boolean isUpdate) {
61 for(Operation interfaceOperation : interfaceOperations) {
62 Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
63 interfaceOperation, resourceId, isUpdate);
64 if (interfaceOperationValidatorResponse.isRight()) {
65 return interfaceOperationValidatorResponse;
68 return Either.left(Boolean.TRUE);
71 private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
72 String resourceId, boolean isUpdate) {
73 ResponseFormatManager responseFormatManager = getResponseFormatManager();
75 Either<Boolean, ResponseFormat> interfaceOperationTypeResponse = isInterfaceOperationTypeValid(interfaceOperation,
76 responseFormatManager, resourceId, isUpdate);
77 if (interfaceOperationTypeResponse.isRight()) {
78 return Either.right(interfaceOperationTypeResponse.right().value());
81 Either<Boolean, ResponseFormat> descriptionResponseEither = isValidDescription(responseFormatManager,
82 interfaceOperation.getDescription());
83 if (descriptionResponseEither.isRight()) {
84 return Either.right(descriptionResponseEither.right().value());
87 Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation,
88 responseFormatManager);
89 if(inputParametersResponse.isRight()) {
90 return Either.right(inputParametersResponse.right().value());
93 Either<Boolean, ResponseFormat> outputParametersResponse = validateOutputParameters(interfaceOperation,
94 responseFormatManager);
95 if(outputParametersResponse.isRight()) {
96 return Either.right(outputParametersResponse.right().value());
99 return Either.left(Boolean.TRUE);
102 private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
103 ResponseFormatManager responseFormatManager,
104 String resourceId, boolean isUpdate) {
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());
112 Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
113 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
114 if (operationTypeRegexValidationResponse.isRight()) {
115 return Either.right(operationTypeRegexValidationResponse.right().value());
118 Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
119 resourceId, isUpdate, responseFormatManager );
120 if(operationTypeUniqueResponse.isRight()) {
121 return Either.right(operationTypeUniqueResponse.right().value());
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);
129 return Either.left(Boolean.TRUE);
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);
141 return Either.left(Boolean.TRUE);
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);
152 return Either.left(Boolean.TRUE);
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);
163 return Either.left(Boolean.TRUE);
166 private boolean isValidOperationType(String operationType) {
167 return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
170 private Either<Boolean, ResponseFormat> validateOperationTypeUnique(
171 Operation interfaceOperation,
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));
185 Collection<InterfaceDefinition> interfaceDefinitions = interfaceOperationOrigin.left().value()
186 .getInterfaces().values();
187 if(CollectionUtils.isEmpty(interfaceDefinitions)){
188 isOperationTypeUnique = true;
189 return Either.left(isOperationTypeUnique);
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);
200 Map<String, String> operationTypes = new HashMap<>();
201 allOperations.forEach(operationType -> operationTypes.put(operationType.getUniqueId(),
202 operationType.getName()) );
205 isOperationTypeUnique = validateOperationTypeUniqueForUpdate(interfaceOperation, operationTypes);
208 if (!operationTypes.values().contains(interfaceOperation.getName())){
209 isOperationTypeUnique = true;
211 return Either.left(isOperationTypeUnique);
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);
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);
230 return Either.left(Boolean.TRUE);
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);
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);
251 return Either.left(Boolean.TRUE);
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());
264 if(!duplicateParamNamesToReturn.isEmpty()) {
265 return Either.right(duplicateParamNamesToReturn);
267 return Either.left(Boolean.TRUE);
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());
279 if(!duplicateParamNamesToReturn.isEmpty()) {
280 return Either.right(duplicateParamNamesToReturn);
282 return Either.left(Boolean.TRUE);
285 private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
286 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
287 .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
289 private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
290 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream()
291 .anyMatch(inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
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;
303 if(entry.getKey().equals(interfaceOperation.getUniqueId()) && !operationTypes.values()
304 .contains(interfaceOperation.getName())){
305 isOperationTypeUnique = true;
308 return isOperationTypeUnique;
311 protected ResponseFormatManager getResponseFormatManager() {
312 return ResponseFormatManager.getInstance();