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 java.util.Collection;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
25 import java.util.Objects;
26 import java.util.Optional;
28 import java.util.regex.Pattern;
29 import java.util.stream.Stream;
30 import org.apache.commons.collections.CollectionUtils;
31 import org.apache.commons.lang.StringUtils;
32 import org.openecomp.sdc.be.components.impl.ResponseFormatManager;
33 import org.openecomp.sdc.be.dao.api.ActionStatus;
34 import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
35 import org.openecomp.sdc.be.model.InputDefinition;
36 import org.openecomp.sdc.be.model.InterfaceDefinition;
37 import org.openecomp.sdc.be.model.Operation;
38 import org.openecomp.sdc.exception.ResponseFormat;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.springframework.stereotype.Component;
43 @Component("interfaceOperationValidation")
44 public class InterfaceOperationValidation {
46 private static final String TYPE_VALIDATION_REGEX = "^[a-zA-Z0-9_]{1,200}$";
48 private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceOperationValidation.class);
50 public Either<Boolean, ResponseFormat> validateInterfaceOperations(InterfaceDefinition inputInterfaceDefinition,
51 org.openecomp.sdc.be.model.Component component, InterfaceDefinition storedInterfaceDefinition,
52 Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate) {
54 Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType =
55 validateAllowedOperationCountOnLocalInterfaceType(inputInterfaceDefinition, storedInterfaceDefinition,
56 globalInterfaceTypes, isUpdate);
57 if (validateAllowedOperationCountOnLocalInterfaceType.isRight()) {
58 return validateAllowedOperationCountOnLocalInterfaceType;
61 Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType =
62 validateAllowedOperationsOnGlobalInterfaceType(inputInterfaceDefinition, globalInterfaceTypes);
63 if (validateAllowedOperationsOnGlobalInterfaceType.isRight()) {
64 return validateAllowedOperationsOnGlobalInterfaceType;
67 Either<Boolean, ResponseFormat> validateOperationNameUniqueness =
68 validateOperationNameUniquenessInCollection(inputInterfaceDefinition.getOperationsMap().values());
69 if (validateOperationNameUniqueness.isRight()) {
70 return validateOperationNameUniqueness;
73 for (Operation interfaceOperation : inputInterfaceDefinition.getOperationsMap().values()) {
74 Either<Boolean, ResponseFormat> interfaceOperationValidatorResponse =
75 validateInterfaceOperation(interfaceOperation, storedInterfaceDefinition, component, isUpdate);
76 if (interfaceOperationValidatorResponse.isRight()) {
77 return interfaceOperationValidatorResponse;
81 return Either.left(Boolean.TRUE);
84 private Either<Boolean, ResponseFormat> validateAllowedOperationCountOnLocalInterfaceType(
85 InterfaceDefinition inputInterfaceDefinition, InterfaceDefinition storedInterfaceDefinition,
86 Map<String, InterfaceDefinition> globalInterfaceTypes, boolean isUpdate) {
88 boolean isInterfaceTypeExistInGlobalType =
89 globalInterfaceTypes.values().stream().map(InterfaceDefinition::getType)
90 .anyMatch(type -> type.equalsIgnoreCase(inputInterfaceDefinition.getType()));
91 if (!isInterfaceTypeExistInGlobalType
92 && (inputInterfaceDefinition.getOperations().size() > 1
93 || (!isUpdate && storedInterfaceDefinition != null
94 && storedInterfaceDefinition.getType()
95 .equalsIgnoreCase(inputInterfaceDefinition.getType())))) {
96 return Either.right(getResponseFormatManager()
97 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_LOCAL_TYPE,
98 inputInterfaceDefinition.getType()));
101 return Either.left(Boolean.TRUE);
104 private Either<Boolean, ResponseFormat> validateAllowedOperationsOnGlobalInterfaceType(
105 InterfaceDefinition interfaceDefinition, Map<String, InterfaceDefinition> globalInterfaceTypes) {
107 if (globalInterfaceTypes != null) {
108 boolean isOperationValidOnGlobalInterfaceType =
109 Stream.of(interfaceDefinition)
110 .filter(interfaceDef -> globalInterfaceTypes.values().stream().anyMatch(
111 interfaceDef1 -> interfaceDef1.getType().equalsIgnoreCase(interfaceDef.getType())))
112 .flatMap(interfaceDef -> interfaceDef.getOperationsMap().values().stream()
113 .map(Operation::getName))
114 .allMatch(operationName -> globalInterfaceTypes.values().stream()
115 .flatMap(interfaceDef -> interfaceDef.getOperationsMap()
118 opName.equalsIgnoreCase(
120 if (!isOperationValidOnGlobalInterfaceType) {
121 return Either.right(getResponseFormatManager()
122 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_INVALID_FOR_GLOBAL_TYPE,
123 interfaceDefinition.getType()));
126 return Either.left(Boolean.TRUE);
129 private Either<Boolean, ResponseFormat> validateOperationNameUniquenessInCollection(
130 Collection<Operation> operationList) {
131 HashSet<String> operationNames = new HashSet<>();
132 for (Operation operation : operationList) {
133 if (!operationNames.add(operation.getName())) {
134 return Either.right(getResponseFormatManager()
135 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE,
136 operation.getName()));
139 return Either.left(Boolean.TRUE);
142 private Either<Boolean, ResponseFormat> validateInterfaceOperation(Operation interfaceOperation,
143 InterfaceDefinition interfaceDefinition, org.openecomp.sdc.be.model.Component component, boolean isUpdate) {
145 ResponseFormatManager responseFormatManager = getResponseFormatManager();
146 Either<Boolean, ResponseFormat> interfaceOperationTypeResponse =
147 isInterfaceOperationTypeValid(interfaceOperation, responseFormatManager, interfaceDefinition, isUpdate);
148 if (interfaceOperationTypeResponse.isRight()) {
149 return Either.right(interfaceOperationTypeResponse.right().value());
152 if (null != interfaceOperation.getInputs()) {
153 Either<Boolean, ResponseFormat> inputParametersResponse =
154 validateInputParameters(interfaceOperation, responseFormatManager);
155 if (inputParametersResponse.isRight()) {
156 return Either.right(inputParametersResponse.right().value());
159 Either<Boolean, ResponseFormat> inputPropertyExistInComponent =
160 validateInputPropertyExistInComponent(interfaceOperation, component, responseFormatManager);
161 if (inputPropertyExistInComponent.isRight()) {
162 return Either.right(inputPropertyExistInComponent.right().value());
167 if (null != interfaceOperation.getOutputs()) {
168 Either<Boolean, ResponseFormat> outputParametersResponse =
169 validateOutputParameters(interfaceOperation, responseFormatManager);
170 if (outputParametersResponse.isRight()) {
171 return Either.right(outputParametersResponse.right().value());
175 return Either.left(Boolean.TRUE);
178 protected ResponseFormatManager getResponseFormatManager() {
179 return ResponseFormatManager.getInstance();
182 private Either<Boolean, ResponseFormat> isInterfaceOperationTypeValid(Operation interfaceOperation,
183 ResponseFormatManager responseFormatManager, InterfaceDefinition interfaceDefinition, boolean isUpdate) {
185 Either<Boolean, ResponseFormat> operationTypeEmptyEither =
186 isOperationTypeEmpty(responseFormatManager, interfaceOperation.getName());
187 if (operationTypeEmptyEither.isRight()) {
188 return Either.right(operationTypeEmptyEither.right().value());
191 Either<Boolean, ResponseFormat> operationTypeRegexValidationResponse =
192 isOperationTypeRegexValid(responseFormatManager, interfaceOperation.getName());
193 if (operationTypeRegexValidationResponse.isRight()) {
194 return Either.right(operationTypeRegexValidationResponse.right().value());
197 Either<Boolean, ResponseFormat> operationTypeUniqueResponse =
198 validateOperationTypeUnique(interfaceOperation, interfaceDefinition, isUpdate);
199 if (operationTypeUniqueResponse.isRight()) {
200 return Either.right(operationTypeUniqueResponse.right().value());
202 if (!operationTypeUniqueResponse.left().value()) {
203 LOGGER.error("Interface Operation type {} already in use ", interfaceOperation.getName());
204 ResponseFormat errorResponse = responseFormatManager.getResponseFormat(
205 ActionStatus.INTERFACE_OPERATION_NAME_ALREADY_IN_USE, interfaceOperation.getName());
206 return Either.right(errorResponse);
208 return Either.left(Boolean.TRUE);
211 private Either<Boolean, ResponseFormat> validateInputParameters(Operation interfaceOperation,
212 ResponseFormatManager responseFormatManager) {
213 if (isInputParameterNameEmpty(interfaceOperation)) {
214 LOGGER.error("Interface operation input parameter name can't be empty");
215 ResponseFormat inputResponse =
216 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_INPUT_NAME_MANDATORY);
217 return Either.right(inputResponse);
220 Either<Boolean, Set<String>> validateInputParametersUniqueResponse =
221 isInputParametersUnique(interfaceOperation);
222 if (validateInputParametersUniqueResponse.isRight()) {
223 LOGGER.error("Interface operation input parameter names {} already in use",
224 validateInputParametersUniqueResponse.right().value());
225 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(
226 ActionStatus.INTERFACE_OPERATION_INPUT_NAME_ALREADY_IN_USE,
227 validateInputParametersUniqueResponse.right().value().toString());
228 return Either.right(inputResponse);
230 return Either.left(Boolean.TRUE);
233 private Either<Boolean, ResponseFormat> validateInputPropertyExistInComponent(Operation operation,
234 org.openecomp.sdc.be.model.Component component, ResponseFormatManager responseFormatManager) {
236 List<OperationInputDefinition> inputListToscaDataDefinition =
237 operation.getInputs().getListToscaDataDefinition();
238 for (OperationInputDefinition inputDefinition : inputListToscaDataDefinition) {
239 if (!validateInputExistsInComponent(inputDefinition, component.getInputs())) {
240 String missingPropertyName = inputDefinition.getInputId().contains(".")
241 ? inputDefinition.getInputId().substring(
242 inputDefinition.getInputId().indexOf('.') + 1)
243 : inputDefinition.getInputId();
244 LOGGER.error("Interface operation input property {} not found in component input properties",
245 missingPropertyName);
246 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(
247 ActionStatus.INTERFACE_OPERATION_INPUT_PROPERTY_NOT_FOUND_IN_COMPONENT, missingPropertyName,
248 component.getComponentType().getValue());
249 return Either.right(inputResponse);
252 return Either.left(Boolean.TRUE);
255 private Either<Boolean, ResponseFormat> validateOutputParameters(Operation interfaceOperation,
256 ResponseFormatManager responseFormatManager) {
257 if (isOutputParameterNameEmpty(interfaceOperation)) {
258 LOGGER.error("Interface operation output parameter name can't be empty");
259 ResponseFormat inputResponse =
260 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_MANDATORY);
261 return Either.right(inputResponse);
264 Either<Boolean, Set<String>> validateOutputParametersUniqueResponse =
265 isOutputParametersUnique(interfaceOperation);
266 if (validateOutputParametersUniqueResponse.isRight()) {
267 LOGGER.error("Interface operation output parameter names {} already in use",
268 validateOutputParametersUniqueResponse.right().value());
269 ResponseFormat inputResponse = responseFormatManager.getResponseFormat(
270 ActionStatus.INTERFACE_OPERATION_OUTPUT_NAME_ALREADY_IN_USE,
271 validateOutputParametersUniqueResponse.right().value().toString());
272 return Either.right(inputResponse);
274 return Either.left(Boolean.TRUE);
277 private Either<Boolean, ResponseFormat> isOperationTypeEmpty(ResponseFormatManager responseFormatManager,
278 String operationType) {
279 if (StringUtils.isEmpty(operationType)) {
280 LOGGER.error("Interface Operation type is mandatory");
281 ResponseFormat errorResponse =
282 responseFormatManager.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_MANDATORY);
283 return Either.right(errorResponse);
285 return Either.left(Boolean.TRUE);
288 private Either<Boolean, ResponseFormat> isOperationTypeRegexValid(ResponseFormatManager responseFormatManager,
289 String operationType) {
290 if (!isValidOperationType(operationType)) {
291 LOGGER.error("Interface Operation type {} is invalid, Operation type should not contain"
292 + "Special character, space, numbers and should not be greater than 200 characters",
294 ResponseFormat errorResponse = responseFormatManager
295 .getResponseFormat(ActionStatus.INTERFACE_OPERATION_NAME_INVALID,
297 return Either.right(errorResponse);
299 return Either.left(Boolean.TRUE);
302 private Either<Boolean, ResponseFormat> validateOperationTypeUnique(Operation interfaceOperation,
303 InterfaceDefinition interfaceDefinition, boolean isUpdate) {
304 boolean isOperationTypeUnique = false;
306 if (interfaceDefinition == null || CollectionUtils.isEmpty(interfaceDefinition.getOperationsMap().values())) {
307 return Either.left(true);
310 Map<String, String> operationTypes = new HashMap<>();
311 interfaceDefinition.getOperationsMap().values()
312 .forEach(operationType -> operationTypes.put(operationType.getUniqueId(), operationType.getName()));
314 if (!operationTypes.values().contains(interfaceOperation.getName())) {
315 isOperationTypeUnique = true;
317 if (!isOperationTypeUnique && isUpdate) {
318 Optional<String> id = operationTypes.entrySet().stream().filter(entry -> Objects.equals(entry.getValue(),
319 interfaceOperation.getName())).map(Map.Entry::getKey).findAny();
320 if (id.isPresent() && id.get().equalsIgnoreCase(interfaceOperation.getUniqueId())) {
321 isOperationTypeUnique = true;
325 return Either.left(isOperationTypeUnique);
328 private Boolean isInputParameterNameEmpty(Operation operationDataDefinition) {
329 return operationDataDefinition.getInputs().getListToscaDataDefinition().stream().anyMatch(
330 inputParam -> inputParam.getName() == null || inputParam.getName().trim().equals(StringUtils.EMPTY));
333 private Either<Boolean, Set<String>> isInputParametersUnique(Operation operationDataDefinition) {
334 Set<String> inputParamNamesSet = new HashSet<>();
335 Set<String> duplicateParamNamesToReturn = new HashSet<>();
336 operationDataDefinition.getInputs().getListToscaDataDefinition().forEach(inputParam -> {
337 if (!inputParamNamesSet.add(inputParam.getName().trim())) {
338 duplicateParamNamesToReturn.add(inputParam.getName().trim());
341 if (!duplicateParamNamesToReturn.isEmpty()) {
342 return Either.right(duplicateParamNamesToReturn);
344 return Either.left(Boolean.TRUE);
347 private boolean validateInputExistsInComponent(OperationInputDefinition input, List<InputDefinition> inputs) {
348 return inputs.stream().anyMatch(inp -> inp.getUniqueId().equals(input.getInputId()))
349 || (input.getInputId().contains(".")
351 .anyMatch(inp -> inp.getUniqueId()
352 .equals(input.getInputId()
355 .lastIndexOf('.')))));
358 private Boolean isOutputParameterNameEmpty(Operation operationDataDefinition) {
359 return operationDataDefinition.getOutputs().getListToscaDataDefinition().stream().anyMatch(
360 outputParam -> outputParam.getName() == null || outputParam.getName().trim().equals(StringUtils.EMPTY));
363 private Either<Boolean, Set<String>> isOutputParametersUnique(Operation operationDataDefinition) {
364 Set<String> outputParamNamesSet = new HashSet<>();
365 Set<String> duplicateParamNamesToReturn = new HashSet<>();
366 operationDataDefinition.getOutputs().getListToscaDataDefinition().forEach(outputParam -> {
367 if (!outputParamNamesSet.add(outputParam.getName().trim())) {
368 duplicateParamNamesToReturn.add(outputParam.getName().trim());
371 if (!duplicateParamNamesToReturn.isEmpty()) {
372 return Either.right(duplicateParamNamesToReturn);
374 return Either.left(Boolean.TRUE);
377 private boolean isValidOperationType(String operationType) {
378 return Pattern.matches(TYPE_VALIDATION_REGEX, operationType);