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;
38 import java.util.Collection;
39 import java.util.HashMap;
40 import java.util.HashSet;
43 import java.util.regex.Pattern;
44 import java.util.stream.Collectors;
46 @Component("interfaceOperationValidation")
47 public class InterfaceOperationValidation {
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;
54 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
56 public Either<Boolean, ResponseFormat> validateInterfaceOperations(
57 Collection<Operation> interfaceOperations,
58 String resourceId, boolean isUpdate) {
60 for(Operation interfaceOperation : interfaceOperations) {
61 Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse = validateInterfaceOperation(
62 interfaceOperation, resourceId, isUpdate);
63 if (interfaceOperationValidatorResponse.isRight()) {
64 return interfaceOperationValidatorResponse;
67 return Either.left(Boolean.TRUE);
70 private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
71 String resourceId, boolean isUpdate) {
72 ResponseFormatManager responseFormatManager = getResponseFormatManager();
74 Either<Boolean, ResponseFormat> interfaceOperationTypeResponse = isInterfaceOperationTypeValid(interfaceOperation,
75 responseFormatManager, resourceId, isUpdate);
76 if (interfaceOperationTypeResponse.isRight()) {
77 return Either.right(interfaceOperationTypeResponse.right().value());
80 Either<Boolean, ResponseFormat> descriptionResponseEither = isValidDescription(responseFormatManager,
81 interfaceOperation.getDescription());
82 if (descriptionResponseEither.isRight()) {
83 return Either.right(descriptionResponseEither.right().value());
86 Either<Boolean, ResponseFormat> inputParametersResponse = validateInputParameters(interfaceOperation,
87 responseFormatManager);
88 if(inputParametersResponse.isRight()) {
89 return Either.right(inputParametersResponse.right().value());
91 return Either.left(Boolean.TRUE);
94 private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
95 ResponseFormatManager responseFormatManager,
96 String resourceId, boolean isUpdate) {
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());
104 Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
105 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
106 if (operationTypeRegexValidationResponse.isRight()) {
107 return Either.right(operationTypeRegexValidationResponse.right().value());
110 Either<Boolean, ResponseFormat> operationTypeUniqueResponse = validateOperationTypeUnique(interfaceOperation,
111 resourceId, isUpdate, responseFormatManager );
112 if(operationTypeUniqueResponse.isRight()) {
113 return Either.right(operationTypeUniqueResponse.right().value());
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);
121 return Either.left(Boolean.TRUE);
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);
133 return Either.left(Boolean.TRUE);
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);
144 return Either.left(Boolean.TRUE);
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);
155 return Either.left(Boolean.TRUE);
158 private boolean isValidOperationType(String operationType) {
159 return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);
162 private Either<Boolean, ResponseFormat> validateOperationTypeUnique(
163 Operation interfaceOperation,
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));
177 Collection<InterfaceDefinition> interfaceDefinitions = interfaceOperationOrigin.left().value()
178 .getInterfaces().values();
179 if(CollectionUtils.isEmpty(interfaceDefinitions)){
180 isOperationTypeUnique = true;
181 return Either.left(isOperationTypeUnique);
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);
192 Map<String, String> operationTypes = new HashMap<>();
193 allOperations.forEach(operationType -> operationTypes.put(operationType.getUniqueId(),
194 operationType.getName()) );
197 isOperationTypeUnique = validateOperationTypeUniqueForUpdate(interfaceOperation, operationTypes);
200 if (!operationTypes.values().contains(interfaceOperation.getName())){
201 isOperationTypeUnique = true;
203 return Either.left(isOperationTypeUnique);
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);
215 return Either.left(Boolean.TRUE);
218 private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) {
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());
228 if(!duplicateParamNamesToReturn.isEmpty()) {
229 return Either.right(duplicateParamNamesToReturn);
231 return Either.left(Boolean.TRUE);
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;
244 if(entry.getKey().equals(interfaceOperation.getUniqueId()) && !operationTypes.values()
245 .contains(interfaceOperation.getName())){
246 isOperationTypeUnique = true;
249 return isOperationTypeUnique;
252 protected ResponseFormatManager getResponseFormatManager() {
253 return ResponseFormatManager.getInstance();