From 1f7c57414533b9886962ede7b19a29669fe7a59a Mon Sep 17 00:00:00 2001 From: mojahidi Date: Fri, 1 Mar 2019 17:50:15 +0530 Subject: Requirement and capabilities feature 1. Enhance Service/VF/PNF to support Req & Cap 2. Added Type fetch APIs to fetch types from global types Change-Id: I2b749ec9da34e488421b8ebe311ccf03c4b7c0fd Issue-ID: SDC-2142 Signed-off-by: mojahidi --- .../components/impl/CapabilitiesBusinessLogic.java | 573 +++++++++++++++++++++ .../be/components/impl/CommonImportManager.java | 5 +- .../impl/RelationshipTypeBusinessLogic.java | 62 +++ .../impl/RelationshipTypeImportManager.java | 109 ++++ .../components/impl/RequirementBusinessLogic.java | 518 +++++++++++++++++++ .../lifecycle/CertificationChangeTransition.java | 8 + .../components/lifecycle/CheckoutTransition.java | 6 + .../components/merge/utils/MergeInstanceUtils.java | 8 +- .../validation/CapabilitiesValidation.java | 266 ++++++++++ .../validation/RequirementValidation.java | 272 ++++++++++ .../org/openecomp/sdc/be/impl/ComponentsUtils.java | 27 + .../sdc/be/servlets/BeGenericServlet.java | 10 + .../sdc/be/servlets/CapabilityServlet.java | 320 ++++++++++++ .../sdc/be/servlets/RequirementServlet.java | 325 ++++++++++++ .../sdc/be/servlets/TypesFetchServlet.java | 207 +++++++- .../sdc/be/servlets/TypesUploadServlet.java | 30 +- .../be/tosca/CapabilityRequirementConverter.java | 63 +-- 17 files changed, 2764 insertions(+), 45 deletions(-) create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CapabilitiesBusinessLogic.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeBusinessLogic.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeImportManager.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RequirementBusinessLogic.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/CapabilitiesValidation.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/RequirementValidation.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/servlets/CapabilityServlet.java create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RequirementServlet.java (limited to 'catalog-be/src/main/java/org') diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CapabilitiesBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CapabilitiesBusinessLogic.java new file mode 100644 index 0000000000..75d5836df6 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CapabilitiesBusinessLogic.java @@ -0,0 +1,573 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.components.impl; + +import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.openecomp.sdc.be.components.validation.CapabilitiesValidation; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.CapabilityTypeDefinition; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.jsontitan.operations.CapabilitiesOperation; +import org.openecomp.sdc.be.model.operations.api.ICapabilityTypeOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Component("capabilitiesBusinessLogic") +public class CapabilitiesBusinessLogic extends BaseBusinessLogic { + private static final Logger LOGGER = LoggerFactory.getLogger(CapabilitiesBusinessLogic.class); + private static final String FAILED_TO_LOCK_COMPONENT_RESPONSE_IS + = "Failed to lock component {}. Response is {}"; + private static final String DELETE_CAPABILITIES = "deleteCapability"; + private static final String GET_CAPABILITIES = "getCapabilities"; + private static final String EXCEPTION_OCCURRED_DURING_CAPABILITIES + = "Exception occurred during {}. Response is {}"; + + @Autowired + private CapabilitiesOperation capabilitiesOperation; + @Autowired + private CapabilitiesValidation capabilitiesValidation; + @Autowired + private ICapabilityTypeOperation capabilityTypeOperation; + + + public void setCapabilitiesValidation(CapabilitiesValidation capabilitiesValidation) { + this.capabilitiesValidation = capabilitiesValidation; + } + + public void setCapabilitiesOperation(CapabilitiesOperation capabilitiesOperation) { + this.capabilitiesOperation = capabilitiesOperation; + } + + public Either, ResponseFormat> createCapabilities( + String componentId, List capabilityDefinitions, + User user, String errorContext, boolean lock) { + validateUserExists(user.getUserId(), errorContext, true); + Either componentEither + = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + Either capabilitiesValidationEither = capabilitiesValidation + .validateCapabilities(capabilityDefinitions, storedComponent, false); + if (capabilitiesValidationEither.isRight()) { + return Either.right(capabilitiesValidationEither.right().value()); + } + + Either lockResult = lockComponentResult(lock, + storedComponent, errorContext); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + Either, StorageOperationStatus> result; + List capabilitiesListStoredInComponent = null; + Map> storedComponentCapabilities + = storedComponent.getCapabilities(); + if (org.apache.commons.collections.MapUtils.isNotEmpty(storedComponentCapabilities)) { + CapabilityDefinition capabilityDefinitionToGetType = capabilityDefinitions.get(0); + if(Objects.isNull(capabilityDefinitionToGetType)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + capabilitiesListStoredInComponent + = getCapabilityStoredInComponentByType(capabilityDefinitionToGetType + .getType(), storedComponentCapabilities); + } + List capabilitiesDefListToCreate; + List capabilitiesToReturn; + if (CollectionUtils.isNotEmpty(capabilitiesListStoredInComponent)) { + capabilitiesDefListToCreate = capabilityDefinitions.stream() + .map(capabilityDefinition -> + initiateNewCapability(storedComponent, capabilityDefinition)) + .collect(Collectors.toList()); + capabilitiesToReturn = capabilitiesDefListToCreate; + capabilitiesDefListToCreate.addAll(capabilitiesListStoredInComponent); + result = capabilitiesOperation.updateCapabilities(componentId, + capabilitiesDefListToCreate); + } else { + capabilitiesToReturn = capabilityDefinitions.stream() + .map(capabilityDefinition -> initiateNewCapability( + storedComponent, capabilityDefinition)) + .collect(Collectors.toList()); + result = capabilitiesOperation.addCapabilities(componentId, capabilitiesToReturn); + } + if (result.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(result.right().value(), + storedComponent.getComponentType()), "")); + } + titanDao.commit(); + return Either.left(capabilitiesToReturn); + } catch (Exception e) { + titanDao.rollback(); + LOGGER.error(EXCEPTION_OCCURRED_DURING_CAPABILITIES, "addOrUpdate", e); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + + public Either, ResponseFormat> updateCapabilities( + String componentId, List capabilityDefinitions, + User user, String errorContext, boolean lock) { + validateUserExists(user.getUserId(), errorContext, true); + Either componentEither + = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + Either capabilitiesValidationEither = capabilitiesValidation + .validateCapabilities(capabilityDefinitions, storedComponent, true); + if (capabilitiesValidationEither.isRight()) { + return Either.right(capabilitiesValidationEither.right().value()); + } + + Either lockResult = lockComponentResult(lock, + storedComponent, errorContext); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + Either, StorageOperationStatus> result; + List capabilitiesListStoredInComponent = null; + Map> storedComponentCapabilities + = storedComponent.getCapabilities(); + if (org.apache.commons.collections.MapUtils.isNotEmpty(storedComponentCapabilities)) { + CapabilityDefinition capabilityDefinitionToGetType = capabilityDefinitions.get(0); + if(Objects.isNull(capabilityDefinitionToGetType)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + capabilitiesListStoredInComponent + = getCapabilityStoredInComponentByType(capabilityDefinitionToGetType + .getType(), storedComponentCapabilities); + } + List capabilitiesDefListToUpdate = new ArrayList<>(); + List capabilitiesToReturn = null; + if (CollectionUtils.isNotEmpty(capabilitiesListStoredInComponent)) { + if (capabilityDefinitions.stream().anyMatch(capabilityDefinition -> + isCapabilityUsedInServiceComposition(capabilityDefinition, storedComponent))) { + LOGGER.error("Capability can't be edited, since it is" + + " used in service composition"); + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_UPDATE_NOT_ALLOWED_USED_IN_COMPOSITION)); + } + for (CapabilityDefinition capabilityDefinitionToUpdate : capabilityDefinitions) { + capabilitiesToReturn = capabilitiesListStoredInComponent.stream() + .filter(capToUpdate -> capToUpdate.getUniqueId() + .equals(capabilityDefinitionToUpdate.getUniqueId())) + .map(capabilityDefinition -> updateCapability(capabilityDefinition, + capabilityDefinitionToUpdate)).collect(Collectors.toList()); + capabilitiesListStoredInComponent.removeIf(capToUpdate -> + capToUpdate.getUniqueId().equals(capabilityDefinitionToUpdate.getUniqueId())); + if (CollectionUtils.isNotEmpty(capabilitiesToReturn)) { + capabilitiesListStoredInComponent.addAll(capabilitiesToReturn); + capabilitiesDefListToUpdate.addAll(capabilitiesListStoredInComponent); + } else { + Either, ResponseFormat> capTypeUpdateEither + = handleCapabilityTypeUpdateWhenNewTypeExist(storedComponent, + storedComponent.getCapabilities(), capabilitiesToReturn, capabilityDefinitionToUpdate); + if (capTypeUpdateEither.isRight()) { + return Either.right(capTypeUpdateEither.right().value()); + } + capabilitiesDefListToUpdate = capTypeUpdateEither.left().value(); + } + } + result = capabilitiesOperation.updateCapabilities(componentId, + capabilitiesDefListToUpdate); + } else { + Either, ResponseFormat> capabilityDefinitionToDelete + = handleCapabilityTypeUpdateWhenNewTypeNotExist(capabilityDefinitions, + storedComponent, storedComponentCapabilities); + if (capabilityDefinitionToDelete != null) { + return capabilityDefinitionToDelete; + } + capabilitiesToReturn = capabilityDefinitions.stream() + .map(capabilityDefinition -> initiateNewCapability( + storedComponent, capabilityDefinition)) + .collect(Collectors.toList()); + result = capabilitiesOperation.addCapabilities(componentId, capabilitiesToReturn); + } + if (result.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(result.right().value(), + storedComponent.getComponentType()), "")); + } + + titanDao.commit(); + return Either.left(capabilitiesToReturn); + } catch (Exception e) { + titanDao.rollback(); + LOGGER.error(EXCEPTION_OCCURRED_DURING_CAPABILITIES, "addOrUpdate", e); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + + private Either, ResponseFormat> handleCapabilityTypeUpdateWhenNewTypeExist( + org.openecomp.sdc.be.model.Component storedComponent, Map> storedComponentCapabilities, + List capabilitiesToReturn, + CapabilityDefinition capabilityDefinitionToUpdate) { + List capabilitiesListStoredInComponent; + List capabilitiesDefsToCreateOrUpdate = new ArrayList<>(); + Optional definitionOptional = storedComponentCapabilities + .values().stream().flatMap(Collection::stream) + .filter(capabilityDefinition -> capabilityDefinition.getUniqueId() + .equals(capabilityDefinitionToUpdate.getUniqueId())).findAny(); + if (!definitionOptional.isPresent()) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_NOT_FOUND, storedComponent.getUniqueId())); + } + CapabilityDefinition capabilityDefinitionToDelete = definitionOptional.get(); + + capabilitiesListStoredInComponent = getCapabilityStoredInComponentByType( + capabilityDefinitionToUpdate.getType(), storedComponentCapabilities); + Either, StorageOperationStatus> deleteCapabilityEither + = deleteCapability(storedComponent, storedComponentCapabilities, capabilityDefinitionToDelete); + if (deleteCapabilityEither.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(deleteCapabilityEither.right().value())); + } + capabilitiesToReturn.add(initiateNewCapability(storedComponent, capabilityDefinitionToUpdate)); + + capabilitiesDefsToCreateOrUpdate.addAll(capabilitiesToReturn); + capabilitiesDefsToCreateOrUpdate.addAll(capabilitiesListStoredInComponent); + return Either.left(capabilitiesDefsToCreateOrUpdate); + } + + private Either, ResponseFormat> handleCapabilityTypeUpdateWhenNewTypeNotExist( + List capabilityDefinitions, + org.openecomp.sdc.be.model.Component storedComponent, + Map> storedComponentCapabilities) { + for (CapabilityDefinition capabilityDefinitionToUpdate : capabilityDefinitions) { + + Optional definitionOptional = storedComponentCapabilities.values() + .stream().flatMap(Collection::stream) + .filter(capabilityDefinition -> capabilityDefinition.getUniqueId() + .equals(capabilityDefinitionToUpdate.getUniqueId())).findAny(); + if (!definitionOptional.isPresent()) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_NOT_FOUND, storedComponent.getUniqueId())); + } + CapabilityDefinition capabilityDefinitionToDelete = definitionOptional.get(); + Boolean isCapabilityUsedInServiceComposition = isCapabilityUsedInServiceComposition( + capabilityDefinitionToDelete, storedComponent); + if (isCapabilityUsedInServiceComposition) { + LOGGER.error("Capability {} can't be edited, since it is used in service composition", + capabilityDefinitionToDelete.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_UPDATE_NOT_ALLOWED_USED_IN_COMPOSITION, + capabilityDefinitionToDelete.getName())); + } + Either, StorageOperationStatus> deleteCapabilityEither + = deleteCapability(storedComponent, storedComponentCapabilities, + capabilityDefinitionToDelete); + if (deleteCapabilityEither.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(deleteCapabilityEither.right().value())); + } + } + return null; + } + + public Either getCapability( + String componentId, + String capabilityToGet, User user, boolean lock) { + validateUserExists(user.getUserId(), GET_CAPABILITIES, true); + Either componentEither + = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + + Either lockResult = lockComponentResult(lock, + storedComponent, GET_CAPABILITIES); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + List capabilityDefinitions = storedComponent.getCapabilities() + .values().stream() + .flatMap(Collection::stream).collect(Collectors.toList()); + if (capabilityDefinitions.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_NOT_FOUND, componentId)); + } + + CapabilityDefinition capabilityDefinitionToReturn; + Optional capabilityDefinitionOptional + = capabilityDefinitions.stream() + .filter(capabilityDefinition -> capabilityDefinition.getUniqueId() + .equals(capabilityToGet)).findAny(); + if (capabilityDefinitionOptional.isPresent()) { + capabilityDefinitionToReturn = capabilityDefinitionOptional.get(); + } else { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_NOT_FOUND, componentId)); + } + + return Either.left(capabilityDefinitionToReturn); + } catch (Exception e) { + LOGGER.error(EXCEPTION_OCCURRED_DURING_CAPABILITIES, "get", e); + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_NOT_FOUND, componentId)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType() + .getValue())); + } + } + } + + public Either deleteCapability( + String componentId, String capabilityIdToDelete, User user, + boolean lock) { + validateUserExists(user.getUserId(), DELETE_CAPABILITIES, true); + Either componentEither + = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + + Either lockResult = lockComponentResult(lock, + storedComponent, DELETE_CAPABILITIES); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + + try { + Map> storedComponentCapabilities + = storedComponent.getCapabilities(); + if (storedComponentCapabilities.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_NOT_FOUND, componentId)); + } + + Optional definitionOptional = storedComponentCapabilities + .values().stream().flatMap(Collection::stream) + .filter(capabilityDefinition -> capabilityDefinition.getUniqueId() + .equals(capabilityIdToDelete)).findAny(); + if (!definitionOptional.isPresent()) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_NOT_FOUND, componentId)); + } + CapabilityDefinition capabilityDefinitionToDelete = definitionOptional.get(); + Boolean isCapabilityUsedInServiceComposition + = isCapabilityUsedInServiceComposition(capabilityDefinitionToDelete, storedComponent); + if (isCapabilityUsedInServiceComposition) { + LOGGER.error("Capability {} can't be deleted, since it is used in service composition", + capabilityDefinitionToDelete.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.CAPABILITY_DELETION_NOT_ALLOWED_USED_IN_COMPOSITION, + capabilityDefinitionToDelete.getName())); + } + + Either, StorageOperationStatus> result + = deleteCapability(storedComponent, storedComponentCapabilities, + capabilityDefinitionToDelete); + if (result.isRight()) { + titanDao.rollback(); + LOGGER.error("Failed to delete capability from component {}. Response is {}", + storedComponent.getName(), result.right().value()); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(result.right().value(), + storedComponent.getComponentType()))); + } + + titanDao.commit(); + return Either.left(capabilityDefinitionToDelete); + } catch (Exception e) { + LOGGER.error(EXCEPTION_OCCURRED_DURING_CAPABILITIES, "delete", e); + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.CAPABILITY_NOT_FOUND)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + + private Either, StorageOperationStatus> deleteCapability( + org.openecomp.sdc.be.model.Component storedComponent, + Map> storedComponentCapabilities, + CapabilityDefinition capabilityDefinitionToDelete) { + List capabilitiesListStoredInComponent = + getCapabilityStoredInComponentByType(capabilityDefinitionToDelete.getType(), + storedComponentCapabilities); + if(capabilitiesListStoredInComponent == null) { + return Either.right(StorageOperationStatus.BAD_REQUEST); + } + capabilitiesListStoredInComponent.removeIf(capabilityDefinition -> + capabilityDefinition.getUniqueId().equals(capabilityDefinitionToDelete.getUniqueId())); + Either, StorageOperationStatus> result; + if (capabilitiesListStoredInComponent.isEmpty()) { + StorageOperationStatus operationStatus = capabilitiesOperation.deleteCapabilities(storedComponent, + capabilityDefinitionToDelete.getType()); + if (StorageOperationStatus.OK.equals(operationStatus)) { + result = Either.left(Collections.singletonList(capabilityDefinitionToDelete)); + } else { + result = Either.right(operationStatus); + } + } else { + result = capabilitiesOperation.updateCapabilities(storedComponent.getUniqueId(), + capabilitiesListStoredInComponent); + } + return result; + } + + + private Either getComponentDetails( + String componentId) { + ComponentParametersView filter = new ComponentParametersView(true); + filter.setIgnoreCapabilities(false); + filter.setIgnoreCapabiltyProperties(false); + Either + componentStorageOperationStatusEither = toscaOperationFacade + .getToscaElement(componentId, filter); + if (componentStorageOperationStatusEither.isRight()) { + StorageOperationStatus errorStatus = componentStorageOperationStatusEither.right().value(); + LOGGER.error("Failed to fetch component information by component id {}, Response is {}", + componentId, errorStatus); + return Either.right(componentsUtils.getResponseFormat(componentsUtils + .convertFromStorageResponse(errorStatus))); + } + return Either.left(componentStorageOperationStatusEither.left().value()); + } + + private Either lockComponentResult( + boolean lock, org.openecomp.sdc.be.model.Component component, + String action) { + if (lock) { + Either lockResult = lockComponent(component.getUniqueId(), + component, action); + if (lockResult.isRight()) { + LOGGER.debug(FAILED_TO_LOCK_COMPONENT_RESPONSE_IS, component.getName(), + lockResult.right().value().getFormattedMessage()); + titanDao.rollback(); + return Either.right(lockResult.right().value()); + } + } + return Either.left(true); + } + + private List getCapabilityStoredInComponentByType( + String capabilityType, Map> capabilities) { + Optional>> entryOptional + = capabilities.entrySet().stream(). + filter(map -> map.getKey().equals(capabilityType)).findFirst(); + return entryOptional.map(Map.Entry::getValue).orElse(null); + + } + + private CapabilityDefinition initiateNewCapability( + org.openecomp.sdc.be.model.Component component, + CapabilityDefinition capabilityDefinition) { + if (StringUtils.isEmpty(capabilityDefinition.getUniqueId())) + capabilityDefinition.setUniqueId(UUID.randomUUID().toString()); + if (StringUtils.isEmpty(capabilityDefinition.getOwnerId())) + capabilityDefinition.setOwnerId(component.getUniqueId()); + if (StringUtils.isEmpty(capabilityDefinition.getOwnerName())) + capabilityDefinition.setOwnerName(component.getName()); + capabilityDefinition.setLeftOccurrences(capabilityDefinition.getMaxOccurrences()); + return capabilityDefinition; + } + + private CapabilityDefinition updateCapability(CapabilityDefinition storedCapability, + CapabilityDefinition capabilityToUpdate) { + storedCapability.setName(capabilityToUpdate.getName()); + storedCapability.setDescription(capabilityToUpdate.getDescription()); + storedCapability.setType(capabilityToUpdate.getType()); + storedCapability.setValidSourceTypes(capabilityToUpdate.getValidSourceTypes()); + storedCapability.setMinOccurrences(capabilityToUpdate.getMinOccurrences()); + storedCapability.setMaxOccurrences(capabilityToUpdate.getMaxOccurrences()); + + return storedCapability; + } + + + private Boolean isCapabilityUsedInServiceComposition( + CapabilityDefinition capabilityDefinition, + org.openecomp.sdc.be.model.Component component) { + Either, StorageOperationStatus> + componentList = toscaOperationFacade + .getParentComponents(component.getUniqueId()); + if (componentList.isRight()) { + return Boolean.FALSE; + } + return componentList.left().value().stream().flatMap(parentComponent -> parentComponent + .getComponentInstancesRelations().stream()) + .flatMap(requirementCapabilityRelDef -> requirementCapabilityRelDef.getRelationships().stream()) + .anyMatch(capabilityRequirementRelationship -> capabilityRequirementRelationship + .getRelation().getCapabilityUid().equals(capabilityDefinition.getUniqueId())); + } + + public Either, ResponseFormat> getAllCapabilityTypes() { + Either, TitanOperationStatus> capabilityTypeCacheAll = + capabilityTypeOperation.getAllCapabilityTypes(); + if (capabilityTypeCacheAll.isRight()) { + TitanOperationStatus operationStatus = capabilityTypeCacheAll.right().value(); + if (TitanOperationStatus.NOT_FOUND == operationStatus) { + BeEcompErrorManager.getInstance().logInternalDataError("FetchCapabilityTypes", "Capability types are " + + "not loaded", + BeEcompErrorManager.ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPE_CANNOT_BE_EMPTY)); + } else { + BeEcompErrorManager.getInstance().logInternalFlowError("FetchCapabilityTypes", "Failed to fetch capability " + + "types", + BeEcompErrorManager.ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + return Either.left(capabilityTypeCacheAll.left().value()); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CommonImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CommonImportManager.java index b60b5c7e09..773dc639a9 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CommonImportManager.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/CommonImportManager.java @@ -173,7 +173,7 @@ public class CommonImportManager { } public enum ElementTypeEnum { - POLICY_TYPE, GROUP_TYPE, DATA_TYPE, CAPABILITY_TYPE, INTERFACE_LIFECYCLE_TYPE + POLICY_TYPE, GROUP_TYPE, DATA_TYPE, CAPABILITY_TYPE, INTERFACE_LIFECYCLE_TYPE, RELATIONSHIP_TYPE } private ActionStatus convertFromStorageResponseForElementType(StorageOperationStatus status, ElementTypeEnum elementTypeEnum) { @@ -191,6 +191,9 @@ public class CommonImportManager { case INTERFACE_LIFECYCLE_TYPE: ret = componentsUtils.convertFromStorageResponseForLifecycleType(status); break; + case RELATIONSHIP_TYPE: + ret = componentsUtils.convertFromStorageResponseForRelationshipType(status); + break; default: ret = componentsUtils.convertFromStorageResponse(status); break; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeBusinessLogic.java new file mode 100644 index 0000000000..4a909785b2 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeBusinessLogic.java @@ -0,0 +1,62 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.Map; + +import fj.data.Either; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.RelationshipTypeDefinition; +import org.openecomp.sdc.be.model.operations.impl.RelationshipTypeOperation; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("relationshipTypeBusinessLogic") +public class RelationshipTypeBusinessLogic { + + @Autowired + private RelationshipTypeOperation relationshipTypeOperation; + + @Autowired + protected ComponentsUtils componentsUtils; + + public Either, ResponseFormat> getAllRelationshipTypes() { + Either, TitanOperationStatus> allRelationshipTypes = + relationshipTypeOperation.getAllRelationshipTypes(); + if (allRelationshipTypes.isRight()) { + TitanOperationStatus operationStatus = allRelationshipTypes.right().value(); + if (TitanOperationStatus.NOT_FOUND == operationStatus) { + BeEcompErrorManager.getInstance().logInternalDataError("FetchRelationshipTypes", "Relationship types " + + "are " + + "not loaded", + BeEcompErrorManager.ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPE_CANNOT_BE_EMPTY)); + } else { + BeEcompErrorManager.getInstance().logInternalFlowError("FetchRelationshipTypes", "Failed to fetch " + + "relationship types", + BeEcompErrorManager.ErrorSeverity.ERROR); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + return Either.left(allRelationshipTypes.left().value()); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeImportManager.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeImportManager.java new file mode 100644 index 0000000000..18671f8caf --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RelationshipTypeImportManager.java @@ -0,0 +1,109 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.components.impl; + +import java.util.List; +import java.util.Map; + +import fj.data.Either; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.CommonImportManager.ElementTypeEnum; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.RelationshipTypeDefinition; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.RelationshipTypeOperation; +import org.openecomp.sdc.be.utils.TypeUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.stereotype.Component; + +@Component("relationshipTypeImportManager") +public class RelationshipTypeImportManager { + + private final RelationshipTypeOperation relationshipTypeOperation; + private final CommonImportManager commonImportManager; + private ComponentsUtils componentsUtils; + + public RelationshipTypeImportManager(RelationshipTypeOperation relationshipTypeOperation, + CommonImportManager commonImportManager) { + this.relationshipTypeOperation = relationshipTypeOperation; + this.commonImportManager = commonImportManager; + } + + public Either>, ResponseFormat> createRelationshipTypes( + String relationshipYml) { + return createRelationshipTypes(relationshipYml, false); + } + + private Either>, ResponseFormat> createRelationshipTypes( + String relationshipTypeYml, boolean inTransaction) { + return commonImportManager.createElementTypes(relationshipTypeYml, + relationshipTypesFromYml -> createRelationshipTypesFromYml(relationshipTypeYml), + relationshipTypesToCreate -> createRelationshipTypesByDao(relationshipTypesToCreate, + inTransaction), ElementTypeEnum.RELATIONSHIP_TYPE); + } + + private Either, ActionStatus> createRelationshipTypesFromYml( + String relationshipTypeYml) { + return commonImportManager.createElementTypesFromYml(relationshipTypeYml, + this::createRelationshipType); + } + + private Either>, ResponseFormat> createRelationshipTypesByDao( + List relationshipTypesToCreate, boolean inTransaction) { + return commonImportManager.createElementTypesByDao(relationshipTypesToCreate, this::validateRelationshipType, + relationshipType -> new ImmutablePair<>(ElementTypeEnum.RELATIONSHIP_TYPE, relationshipType.getType()), + relationshipTypeName -> relationshipTypeOperation.getRelationshipTypeByName(relationshipTypeName) + .right().map(DaoStatusConverter::convertTitanStatusToStorageStatus), + relationshipType -> relationshipTypeOperation.addRelationshipType(relationshipType, inTransaction), + (newRelationshipType, oldRelationshipType) -> relationshipTypeOperation + .updateRelationshipType(newRelationshipType, oldRelationshipType, inTransaction)); + } + + + private Either validateRelationshipType(RelationshipTypeDefinition relationshipType) { + Either result = Either.left(ActionStatus.OK); + if (relationshipType.getType() == null) { + ResponseFormat responseFormat = + componentsUtils.getResponseFormat(ActionStatus.MISSING_RELATIONSHIP_TYPE, relationshipType.getType()); + result = Either.right(responseFormat); + } + return result; + } + + private RelationshipTypeDefinition createRelationshipType(String relationshipTypeName, + Map toscaJson) { + RelationshipTypeDefinition relationshipType = new RelationshipTypeDefinition(); + + relationshipType.setType(relationshipTypeName); + + // Description + commonImportManager.setField(toscaJson, TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName(), + relationshipType::setDescription); + // Derived From + commonImportManager.setField(toscaJson, TypeUtils.ToscaTagNamesEnum.DERIVED_FROM.getElementName(), + relationshipType::setDerivedFrom); + // Properties + commonImportManager.setPropertiesMap(toscaJson, relationshipType::setProperties); + //valid-target-types + if(toscaJson.get("valid_target_types") instanceof List) + relationshipType.setValidTargetTypes((List) toscaJson.get("valid_target_types")); + + return relationshipType; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RequirementBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RequirementBusinessLogic.java new file mode 100644 index 0000000000..c07a9fc09f --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/RequirementBusinessLogic.java @@ -0,0 +1,518 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.components.impl; + +import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.openecomp.sdc.be.components.validation.RequirementValidation; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.jsontitan.operations.RequirementOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Component("requirementBusinessLogic") +public class RequirementBusinessLogic extends BaseBusinessLogic { + private static final Logger LOGGER = LoggerFactory.getLogger(RequirementBusinessLogic.class); + private static final String FAILED_TO_LOCK_COMPONENT_RESPONSE_IS + = "Failed to lock component {}. Response is {}"; + private static final String DELETE_REQUIREMENTS = "deleteRequirement"; + private static final String GET_REQUIREMENTS = "getRequirements"; + private static final String EXCEPTION_OCCURRED_DURING_REQUIREMENTS + = "Exception occurred during {}. Response is {}"; + + @Autowired + private RequirementOperation requirementOperation; + @Autowired + private RequirementValidation requirementValidation; + + + public void setRequirementOperation(RequirementOperation requirementOperation) { + this.requirementOperation = requirementOperation; + } + + public void setRequirementValidation(RequirementValidation requirementValidation) { + this.requirementValidation = requirementValidation; + } + + public Either, ResponseFormat> createRequirements( + String componentId, List requirementDefinitions, + User user, String errorContext, boolean lock) { + validateUserExists(user.getUserId(), errorContext, true); + Either componentEither + = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + + Either requirementsValidationEither = requirementValidation + .validateRequirements(requirementDefinitions, storedComponent, false); + if (requirementsValidationEither.isRight()) { + return Either.right(requirementsValidationEither.right().value()); + } + + Either lockResult = lockComponentResult(lock, + storedComponent, errorContext); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + + try { + Either, StorageOperationStatus> result; + List requirementsListStoredInComponent = null; + Map> storedComponentRequirements + = storedComponent.getRequirements(); + if (org.apache.commons.collections.MapUtils.isNotEmpty(storedComponentRequirements)) { + RequirementDefinition requirementDefinitionToGetType = requirementDefinitions.get(0); + if(Objects.isNull(requirementDefinitionToGetType)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + requirementsListStoredInComponent + = getRequirementStoredInComponentByType(requirementDefinitionToGetType + .getCapability(), storedComponentRequirements); + } + List requirementsToReturn; + if (org.apache.commons.collections.CollectionUtils + .isNotEmpty(requirementsListStoredInComponent)) { + List requirementDefToCreate = requirementDefinitions.stream() + .map(requirementDefinition -> initiateNewRequirement(storedComponent, requirementDefinition)) + .collect(Collectors.toList()); + requirementsToReturn = requirementDefToCreate; + requirementDefToCreate.addAll(requirementsListStoredInComponent); + result = requirementOperation.updateRequirement(componentId, requirementDefToCreate); + } else { + requirementsToReturn = requirementDefinitions.stream().map(requirementDefinition -> + initiateNewRequirement(storedComponent, requirementDefinition)) + .collect(Collectors.toList()); + result = requirementOperation.addRequirement(componentId, requirementsToReturn); + } + if (result.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(result.right().value(), + storedComponent.getComponentType()), "")); + } + titanDao.commit(); + return Either.left(requirementsToReturn); + } catch (Exception e) { + titanDao.rollback(); + LOGGER.error(EXCEPTION_OCCURRED_DURING_REQUIREMENTS, "addOrUpdate", e); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + + public Either, ResponseFormat> updateRequirements( + String componentId, List requirementDefinitions, + User user, String errorContext, boolean lock) { + validateUserExists(user.getUserId(), errorContext, true); + Either componentEither + = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + + Either requirementsValidationEither = requirementValidation + .validateRequirements(requirementDefinitions, storedComponent, true); + if (requirementsValidationEither.isRight()) { + return Either.right(requirementsValidationEither.right().value()); + } + + Either lockResult = lockComponentResult(lock, + storedComponent, errorContext); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + Either, StorageOperationStatus> result; + List requirementsListStoredInComponent = null; + Map> storedComponentRequirements + = storedComponent.getRequirements(); + if (org.apache.commons.collections.MapUtils.isNotEmpty(storedComponentRequirements)) { + RequirementDefinition requirementDefinitionToGetType = requirementDefinitions.get(0); + if(Objects.isNull(requirementDefinitionToGetType)) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + requirementsListStoredInComponent + = getRequirementStoredInComponentByType(requirementDefinitionToGetType + .getCapability(), storedComponentRequirements); + } + List requirementsToReturn = null; + if (org.apache.commons.collections.CollectionUtils + .isNotEmpty(requirementsListStoredInComponent)) { + List requirementDefToUpdate = new ArrayList<>(); + if (requirementDefinitions.stream().anyMatch(requirementDefinition -> + isRequirementUsedInServiceComposition(requirementDefinition, storedComponent))) { + LOGGER.error("Requirement can't be edited, since it is used in service composition"); + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .REQUIREMENT_UPDATE_NOT_ALLOWED_USED_IN_COMPOSITION)); + } + for (RequirementDefinition requirementDefinitionToUpdate : requirementDefinitions) { + requirementsToReturn = requirementsListStoredInComponent.stream() + .filter(reqToUpdate -> reqToUpdate.getUniqueId() + .equals(requirementDefinitionToUpdate.getUniqueId())) + .map(requirementDefinition -> updateRequirement(requirementDefinition, + requirementDefinitionToUpdate)).collect(Collectors.toList()); + requirementsListStoredInComponent.removeIf(reqToUpdate -> + reqToUpdate.getUniqueId().equals(requirementDefinitionToUpdate.getUniqueId())); + + if (CollectionUtils.isNotEmpty(requirementsToReturn)) { + requirementsListStoredInComponent.addAll(requirementsToReturn); + requirementDefToUpdate.addAll(requirementsListStoredInComponent); + } else { + Either, ResponseFormat> updateCapTypeEither + = handleUpdateRequirementCapabilityWhenNewCapabilityExist(storedComponent, + storedComponentRequirements, + requirementsToReturn, requirementDefinitionToUpdate); + if (updateCapTypeEither.isRight()) { + return Either.right(updateCapTypeEither.right().value()); + } + requirementDefToUpdate = updateCapTypeEither.left().value(); + } + } + result = requirementOperation.updateRequirement(componentId, requirementDefToUpdate); + } else { + Either, ResponseFormat> requirementDefinitionToDelete + = handleRequirementCapabilityUpdateWhenNewCapabilityNotExist(requirementDefinitions, + storedComponent, storedComponentRequirements); + if (requirementDefinitionToDelete != null) { + return requirementDefinitionToDelete; + } + requirementsToReturn = requirementDefinitions.stream().map(requirementDefinition -> + initiateNewRequirement(storedComponent, requirementDefinition)) + .collect(Collectors.toList()); + result = requirementOperation.addRequirement(componentId, requirementsToReturn); + } + if (result.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat( + componentsUtils.convertFromStorageResponse(result.right().value(), + storedComponent.getComponentType()), "")); + } + titanDao.commit(); + return Either.left(requirementsToReturn); + } catch (Exception e) { + titanDao.rollback(); + LOGGER.error(EXCEPTION_OCCURRED_DURING_REQUIREMENTS, "addOrUpdate", e); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + + private Either, ResponseFormat> handleUpdateRequirementCapabilityWhenNewCapabilityExist( + org.openecomp.sdc.be.model.Component storedComponent, + Map> storedComponentRequirements, + List requirementsToReturn, + RequirementDefinition requirementDefinitionToUpdate) { + List requirementsListStoredInComponent; + List requirementDefsToCreateOrUpdate = new ArrayList<>(); + Optional definitionOptional = storedComponentRequirements + .values().stream().flatMap(Collection::stream) + .filter(requirementDefinition -> requirementDefinition.getUniqueId() + .equals(requirementDefinitionToUpdate.getUniqueId())).findAny(); + if (!definitionOptional.isPresent()) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.REQUIREMENT_NOT_FOUND, storedComponent.getUniqueId())); + } + RequirementDefinition requirementDefinitionToDelete = definitionOptional.get(); + + requirementsListStoredInComponent = getRequirementStoredInComponentByType( + requirementDefinitionToUpdate.getCapability(), storedComponentRequirements); + Either, StorageOperationStatus> deleteRequirementEither + = deleteRequirement(storedComponent, storedComponentRequirements, requirementDefinitionToDelete); + if (deleteRequirementEither.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(deleteRequirementEither.right().value())); + } + requirementsToReturn.add(initiateNewRequirement(storedComponent, requirementDefinitionToUpdate)); + + requirementDefsToCreateOrUpdate.addAll(requirementsToReturn); + requirementDefsToCreateOrUpdate.addAll(requirementsListStoredInComponent); + return Either.left(requirementDefsToCreateOrUpdate); + } + + private Either, ResponseFormat> handleRequirementCapabilityUpdateWhenNewCapabilityNotExist( + List requirementDefinitions, + org.openecomp.sdc.be.model.Component storedComponent, + Map> storedComponentRequirements) { + for (RequirementDefinition requirementDefinitionToUpdate : requirementDefinitions) { + + Optional definitionOptional = storedComponentRequirements + .values().stream().flatMap(Collection::stream) + .filter(requirementDefinition -> requirementDefinition.getUniqueId() + .equals(requirementDefinitionToUpdate.getUniqueId())).findAny(); + if (!definitionOptional.isPresent()) { + return Either.right(componentsUtils.getResponseFormat( + ActionStatus.REQUIREMENT_NOT_FOUND, storedComponent.getUniqueId())); + } + RequirementDefinition requirementDefinitionToDelete = definitionOptional.get(); + Boolean isRequirementUsedInServiceComposition + = isRequirementUsedInServiceComposition(requirementDefinitionToDelete, storedComponent); + if (isRequirementUsedInServiceComposition) { + LOGGER.error("Requirement {} can't be edited, since it is used in service composition", + requirementDefinitionToDelete.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .REQUIREMENT_UPDATE_NOT_ALLOWED_USED_IN_COMPOSITION, + requirementDefinitionToDelete.getName())); + } + Either, StorageOperationStatus> deleteRequirementEither + = deleteRequirement(storedComponent, storedComponentRequirements, requirementDefinitionToDelete); + if (deleteRequirementEither.isRight()) { + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(deleteRequirementEither.right().value())); + } + } + return null; + } + + public Either getRequirement(String componentId, + String requirementIdToGet, User user, boolean lock) { + validateUserExists(user.getUserId(), GET_REQUIREMENTS, true); + Either componentEither = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + + Either lockResult = lockComponentResult(lock, storedComponent, GET_REQUIREMENTS); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + try { + + List requirementDefinitions = storedComponent.getRequirements().values().stream() + .flatMap(Collection::stream).collect(Collectors.toList()); + if (requirementDefinitions.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.REQUIREMENT_NOT_FOUND, componentId)); + } + + RequirementDefinition requirementDefinitionToReturn; + Optional requirementDefinitionOptional = requirementDefinitions.stream() + .filter(requirementDefinition -> requirementDefinition.getUniqueId().equals(requirementIdToGet)).findAny(); + if (requirementDefinitionOptional.isPresent()) { + requirementDefinitionToReturn = requirementDefinitionOptional.get(); + } else { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.REQUIREMENT_NOT_FOUND, componentId)); + } + return Either.left(requirementDefinitionToReturn); + } catch (Exception e) { + LOGGER.error(EXCEPTION_OCCURRED_DURING_REQUIREMENTS, "get", e); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.REQUIREMENT_NOT_FOUND, componentId)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + + public Either deleteRequirement(String componentId, + String requirementIdToDelete, + User user, boolean lock) { + validateUserExists(user.getUserId(), DELETE_REQUIREMENTS, true); + Either componentEither + = getComponentDetails(componentId); + if (componentEither.isRight()) { + return Either.right(componentEither.right().value()); + } + org.openecomp.sdc.be.model.Component storedComponent = componentEither.left().value(); + + Either lockResult = lockComponentResult(lock, storedComponent, DELETE_REQUIREMENTS); + if (lockResult.isRight()) { + return Either.right(lockResult.right().value()); + } + + try { + Map> storedComponentRequirements = storedComponent.getRequirements(); + if (storedComponentRequirements.isEmpty()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.REQUIREMENT_NOT_FOUND, componentId)); + } + + Optional definitionOptional = storedComponentRequirements + .values().stream().flatMap(Collection::stream) + .filter(requirementDefinition -> requirementDefinition.getUniqueId() + .equals(requirementIdToDelete)).findAny(); + if (!definitionOptional.isPresent()) { + return Either.right(componentsUtils.getResponseFormat(ActionStatus.REQUIREMENT_NOT_FOUND, componentId)); + } + RequirementDefinition requirementDefinitionToDelete = definitionOptional.get(); + + Boolean isRequirementUsedInServiceComposition + = isRequirementUsedInServiceComposition(requirementDefinitionToDelete, storedComponent); + if (isRequirementUsedInServiceComposition) { + LOGGER.error("Requirement {} can't be deleted, since it is used in service composition", + requirementDefinitionToDelete.getUniqueId()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus + .CAPABILITY_DELETION_NOT_ALLOWED_USED_IN_COMPOSITION, + requirementDefinitionToDelete.getName())); + } + + Either, StorageOperationStatus> result + = deleteRequirement(storedComponent, storedComponentRequirements, requirementDefinitionToDelete); + if (result.isRight()) { + titanDao.rollback(); + LOGGER.error("Failed to delete requirement from component {}. Response is {}", + storedComponent.getName(), result.right().value()); + return Either.right(componentsUtils.getResponseFormat(componentsUtils + .convertFromStorageResponse(result.right().value(), storedComponent.getComponentType()))); + } + titanDao.commit(); + return Either.left(requirementDefinitionToDelete); + } catch (Exception e) { + LOGGER.error(EXCEPTION_OCCURRED_DURING_REQUIREMENTS, "delete", e); + titanDao.rollback(); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.REQUIREMENT_NOT_FOUND)); + } finally { + if (lockResult.isLeft() && lockResult.left().value()) { + graphLockOperation.unlockComponent(storedComponent.getUniqueId(), + NodeTypeEnum.getByNameIgnoreCase(storedComponent.getComponentType().getValue())); + } + } + } + + private Either, StorageOperationStatus> deleteRequirement( + org.openecomp.sdc.be.model.Component storedComponent, Map> storedComponentRequirements, + RequirementDefinition requirementDefinitionToDelete) { + List requirementStoredInComponentByType = + getRequirementStoredInComponentByType(requirementDefinitionToDelete.getCapability(), + storedComponentRequirements); + if(requirementStoredInComponentByType == null) { + return Either.right(StorageOperationStatus.BAD_REQUEST); + } + requirementStoredInComponentByType.removeIf(requirementDefinition -> + requirementDefinition.getUniqueId().equals(requirementDefinitionToDelete.getUniqueId())); + Either, StorageOperationStatus> result; + if (requirementStoredInComponentByType.isEmpty()) { + + StorageOperationStatus operationStatus = requirementOperation.deleteRequirements(storedComponent, + requirementDefinitionToDelete.getCapability()); + if (operationStatus.equals(StorageOperationStatus.OK)) { + result = Either.left(Collections.singletonList(requirementDefinitionToDelete)); + } else { + result = Either.right(operationStatus); + } + } else { + result = requirementOperation.updateRequirement(storedComponent.getUniqueId(), + requirementStoredInComponentByType); + } + return result; + } + + private Either getComponentDetails(String componentId) { + ComponentParametersView filter = new ComponentParametersView(true); + filter.setIgnoreRequirements(false); + Either componentStorageOperationStatusEither + = toscaOperationFacade.getToscaElement(componentId, filter); + if (componentStorageOperationStatusEither.isRight()) { + StorageOperationStatus errorStatus = componentStorageOperationStatusEither.right().value(); + LOGGER.error("Failed to fetch component information by component id {}, Response is {}", componentId, errorStatus); + return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(errorStatus))); + } + return Either.left(componentStorageOperationStatusEither.left().value()); + } + + private Either lockComponentResult(boolean lock, + org.openecomp.sdc.be.model.Component component, + String action) { + if (lock) { + Either lockResult = lockComponent(component.getUniqueId(), component, action); + if (lockResult.isRight()) { + LOGGER.debug(FAILED_TO_LOCK_COMPONENT_RESPONSE_IS, component.getName(), + lockResult.right().value().getFormattedMessage()); + titanDao.rollback(); + return Either.right(lockResult.right().value()); + } + } + return Either.left(true); + } + + private List getRequirementStoredInComponentByType( + String capabilityType, Map> requirements) { + + Optional>> entryOptional + = requirements.entrySet().stream().filter(map -> map.getKey().equals(capabilityType)).findFirst(); + return entryOptional.map(Map.Entry::getValue).orElse(null); + + } + + private RequirementDefinition initiateNewRequirement(org.openecomp.sdc.be.model.Component component, + RequirementDefinition requirementDefinition) { + if (StringUtils.isEmpty(requirementDefinition.getUniqueId())) + requirementDefinition.setUniqueId(UUID.randomUUID().toString()); + if (StringUtils.isEmpty(requirementDefinition.getOwnerId())) + requirementDefinition.setOwnerId(component.getUniqueId()); + if (StringUtils.isEmpty(requirementDefinition.getOwnerName())) + requirementDefinition.setOwnerName(component.getName()); + requirementDefinition.setLeftOccurrences(requirementDefinition.getMaxOccurrences()); + return requirementDefinition; + } + + private RequirementDefinition updateRequirement(RequirementDefinition storedRequirement, + RequirementDefinition requirementToUpdate) { + storedRequirement.setName(requirementToUpdate.getName()); + storedRequirement.setCapability(requirementToUpdate.getCapability()); + storedRequirement.setNode(requirementToUpdate.getNode()); + storedRequirement.setRelationship(requirementToUpdate.getRelationship()); + storedRequirement.setMinOccurrences(requirementToUpdate.getMinOccurrences()); + storedRequirement.setMaxOccurrences(requirementToUpdate.getMaxOccurrences()); + return storedRequirement; + } + + private Boolean isRequirementUsedInServiceComposition(RequirementDefinition requirementDefinition, + org.openecomp.sdc.be.model.Component component) { + Either, StorageOperationStatus> componentList + = toscaOperationFacade.getParentComponents(component.getUniqueId()); + if (componentList.isRight()) { + return Boolean.FALSE; + } + return componentList.left().value().stream() + .flatMap(parentComponent -> parentComponent.getComponentInstancesRelations() + .stream()).flatMap(requirementCapabilityRelDef -> requirementCapabilityRelDef.getRelationships().stream()) + .anyMatch(capabilityRequirementRelationship -> capabilityRequirementRelationship.getRelation() + .getRequirementUid().equals(requirementDefinition.getUniqueId())); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationChangeTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationChangeTransition.java index e6a6491aed..2ca6ca41cb 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationChangeTransition.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CertificationChangeTransition.java @@ -37,6 +37,7 @@ import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.jsontitan.utils.ModelConverter; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.tosca.ToscaUtils; import org.openecomp.sdc.be.user.Role; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; @@ -193,6 +194,7 @@ public class CertificationChangeTransition extends LifeCycleTransition { } } updateCalculatedCapabilitiesRequirements(componentAfterCertification); + updateCapReqOwnerId(componentAfterCertification); result = Either.left(componentAfterCertification); return result; } finally { @@ -212,6 +214,12 @@ public class CertificationChangeTransition extends LifeCycleTransition { } + private void updateCapReqOwnerId(Component component) { + if(component.isTopologyTemplate() && ToscaUtils.isNotComplexVfc(component)) { + toscaOperationFacade.updateCapReqOwnerId(component.getUniqueId()); + } + } + private void updateCalculatedCapabilitiesRequirements(Component certifiedComponent) { if(certifiedComponent.getComponentType() == ComponentTypeEnum.SERVICE){ toscaOperationFacade.updateNamesOfCalculatedCapabilitiesRequirements(certifiedComponent.getUniqueId()); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java index 525df14ef8..0c4464239e 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/CheckoutTransition.java @@ -123,6 +123,7 @@ public class CheckoutTransition extends LifeCycleTransition { } } handleCalculatedCapabilitiesRequirements(clonedComponent); + updateCapReqOwnerId(clonedComponent); } } finally { @@ -148,6 +149,11 @@ public class CheckoutTransition extends LifeCycleTransition { } } + private void updateCapReqOwnerId(Component component) { + if(component.isTopologyTemplate() && ToscaUtils.isNotComplexVfc(component)) { + toscaOperationFacade.updateCapReqOwnerId(component.getUniqueId()); + } + } private StorageOperationStatus upgradeToLatestGenericData(Component clonedComponent) { StorageOperationStatus updateStatus = StorageOperationStatus.OK; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/utils/MergeInstanceUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/utils/MergeInstanceUtils.java index 06da9ecd98..55cf75b769 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/utils/MergeInstanceUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/merge/utils/MergeInstanceUtils.java @@ -122,11 +122,17 @@ public class MergeInstanceUtils { else { instanceBuildingBlocks = ComponentInstanceBuildingBlocks.of(new ArrayList<>(), singletonList(componentInstance)); } + return instanceBuildingBlocks; } else { instanceBuildingBlocks = recursiveScanForAtomicBuildingBlocks(component); + if(org.apache.commons.collections.MapUtils.isNotEmpty(component.getCapabilities()) || org.apache.commons.collections.MapUtils.isNotEmpty(component.getRequirements())) { + ComponentInstanceBuildingBlocks nonAtomicBlocks = ComponentInstanceBuildingBlocks.of(new ArrayList<>(), singletonList(componentInstance)); + return ComponentInstanceBuildingBlocks.merge(instanceBuildingBlocks, nonAtomicBlocks); + } + return instanceBuildingBlocks; + } - return instanceBuildingBlocks; } public RelationMergeInfo mapRelationCapability(RequirementCapabilityRelDef relDef, List capsOwners) { diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/CapabilitiesValidation.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/CapabilitiesValidation.java new file mode 100644 index 0000000000..9590ec97d9 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/CapabilitiesValidation.java @@ -0,0 +1,266 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.components.validation; + +import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; +import org.openecomp.sdc.be.components.impl.ResponseFormatManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Component("capabilitiesValidation") +public class CapabilitiesValidation { + private static final Logger LOGGER = LoggerFactory.getLogger(CapabilitiesValidation.class); + private static final String CAPABILITY_NOT_FOUND_IN_COMPONENT = "Capability not found in component {} "; + private static final Pattern NAME_VALIDATION_REGEX_PATTERN = Pattern.compile("^[a-zA-Z0-9_.]*$"); + + public Either validateCapabilities( + Collection capabilities, + org.openecomp.sdc.be.model.Component component, boolean isUpdate) { + + for(CapabilityDefinition capabilityDefinition : capabilities) { + Either validateCapabilityResponse = validateCapability( + capabilityDefinition, component, isUpdate); + if (validateCapabilityResponse.isRight()) { + return validateCapabilityResponse; + } + } + return Either.left(Boolean.TRUE); + } + + private Either validateCapability(CapabilityDefinition capabilityDefinition, + org.openecomp.sdc.be.model.Component component, + boolean isUpdate) { + ResponseFormatManager responseFormatManager = getResponseFormatManager(); + + if(isUpdate) { + Either capabilityExistValidationEither + = isCapabilityExist(capabilityDefinition, responseFormatManager, component); + if (capabilityExistValidationEither.isRight()) { + return Either.right(capabilityExistValidationEither.right().value()); + } + } + Either capabilityNameValidationResponse + = validateCapabilityName(capabilityDefinition, responseFormatManager, component, isUpdate); + if (capabilityNameValidationResponse.isRight()) { + return Either.right(capabilityNameValidationResponse.right().value()); + } + Either capabilityTypeEmptyEither = + isCapabilityTypeEmpty(responseFormatManager, capabilityDefinition.getType()); + if (capabilityTypeEmptyEither.isRight()) { + return Either.right(capabilityTypeEmptyEither.right().value()); + } + + Either capabilityOccurrencesValidationEither = + validateOccurrences(capabilityDefinition, responseFormatManager); + if (capabilityOccurrencesValidationEither.isRight()) { + return Either.right(capabilityOccurrencesValidationEither.right().value()); + } + + return Either.left(Boolean.FALSE); + } + + private Either validateOccurrences(CapabilityDefinition capabilityDefinition, + ResponseFormatManager responseFormatManager) { + String maxOccurrences = capabilityDefinition.getMaxOccurrences(); + String minOccurrences = capabilityDefinition.getMinOccurrences(); + if(StringUtils.isNotEmpty(maxOccurrences) && StringUtils.isNotEmpty(minOccurrences)) { + Either capabilityOccurrencesValidationEither = + validateOccurrences(responseFormatManager, minOccurrences, + maxOccurrences); + if (capabilityOccurrencesValidationEither.isRight()) { + return Either.right(capabilityOccurrencesValidationEither.right().value()); + } + } + return Either.left(Boolean.TRUE); + } + + private Either isCapabilityExist(CapabilityDefinition definition, + ResponseFormatManager responseFormatManager, + org.openecomp.sdc.be.model.Component component) { + Map> componentCapabilities = component.getCapabilities(); + if(MapUtils.isEmpty(componentCapabilities)){ + LOGGER.error(CAPABILITY_NOT_FOUND_IN_COMPONENT, component.getUniqueId()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .CAPABILITY_NOT_FOUND, component.getUniqueId()); + return Either.right(errorResponse); + } + + List capabilityDefinitionList = componentCapabilities.values() + .stream().flatMap(Collection::stream).collect(Collectors.toList()); + if(CollectionUtils.isEmpty(capabilityDefinitionList)){ + LOGGER.error(CAPABILITY_NOT_FOUND_IN_COMPONENT, component.getUniqueId()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .CAPABILITY_NOT_FOUND, component.getUniqueId()); + return Either.right(errorResponse); + } + boolean isCapabilityExist = capabilityDefinitionList.stream().anyMatch(capabilityDefinition -> + capabilityDefinition.getUniqueId().equalsIgnoreCase(definition.getUniqueId())); + + if(!isCapabilityExist) { + LOGGER.error(CAPABILITY_NOT_FOUND_IN_COMPONENT, component.getUniqueId()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .CAPABILITY_NOT_FOUND, component.getUniqueId()); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either validateCapabilityName(CapabilityDefinition capabilityDefinition, + ResponseFormatManager responseFormatManager, + org.openecomp.sdc.be.model.Component component, + boolean isUpdate) { + Either capabilityNameEmptyEither = + isCapabilityNameEmpty(responseFormatManager, capabilityDefinition.getName()); + if (capabilityNameEmptyEither.isRight()) { + return Either.right(capabilityNameEmptyEither.right().value()); + } + + Either capabilityNameRegexValidationResponse = + isCapabilityNameRegexValid(responseFormatManager, capabilityDefinition.getName()); + if (capabilityNameRegexValidationResponse.isRight()) { + return Either.right(capabilityNameRegexValidationResponse.right().value()); + } + + Either operationTypeUniqueResponse + = validateCapabilityNameUnique(capabilityDefinition, component, isUpdate ); + if(operationTypeUniqueResponse.isRight()) { + return Either.right(operationTypeUniqueResponse.right().value()); + } + if (!operationTypeUniqueResponse.left().value()) { + LOGGER.error("Capability name {} already in use ", capabilityDefinition.getName()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .CAPABILITY_NAME_ALREADY_IN_USE, capabilityDefinition.getName()); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either isCapabilityNameEmpty( + ResponseFormatManager responseFormatManager, String capabilityName) { + if (StringUtils.isEmpty(capabilityName)) { + LOGGER.error("Capability Name is mandatory"); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .CAPABILITY_NAME_MANDATORY); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either isCapabilityTypeEmpty( + ResponseFormatManager responseFormatManager, String capabilityType) { + if (StringUtils.isEmpty(capabilityType)) { + LOGGER.error("Capability type is mandatory"); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .CAPABILITY_TYPE_MANDATORY); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + + private Either validateOccurrences ( + ResponseFormatManager responseFormatManager, + String minOccurrences, String maxOccurrences ) { + if(StringUtils.isNotEmpty(maxOccurrences)&& "UNBOUNDED".equalsIgnoreCase(maxOccurrences) + && Integer.parseInt(minOccurrences) >= 0) { + return Either.left(Boolean.TRUE); + } else if(Integer.parseInt(minOccurrences) < 0) { + LOGGER.debug("Invalid occurrences format.low_bound occurrence negative {}", minOccurrences); + ResponseFormat responseFormat = responseFormatManager.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } else if(Integer.parseInt(maxOccurrences) < Integer.parseInt(minOccurrences)){ + LOGGER.error("Capability maxOccurrences should be greater than minOccurrences"); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .MAX_OCCURRENCES_SHOULD_BE_GREATER_THAN_MIN_OCCURRENCES); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either validateCapabilityNameUnique( + CapabilityDefinition capabilityDefinition, + org.openecomp.sdc.be.model.Component component, + boolean isUpdate) { + boolean isCapabilityNameUnique = false; + + Map> componentCapabilities = component.getCapabilities(); + if(MapUtils.isEmpty(componentCapabilities)){ + return Either.left(true); + } + + List capabilityDefinitionList = componentCapabilities.values() + .stream().flatMap(Collection::stream).collect(Collectors.toList()); + + if(CollectionUtils.isEmpty(capabilityDefinitionList)){ + return Either.left(true); + } + + Map capabilityNameMap = new HashMap<>(); + capabilityDefinitionList.forEach(capability -> capabilityNameMap + .put(capability.getUniqueId(), capability.getName())); + + if (!capabilityNameMap.values().contains(capabilityDefinition.getName())){ + isCapabilityNameUnique = true; + } + if (!isCapabilityNameUnique && isUpdate){ + List> capNamesEntries = capabilityNameMap.entrySet() + .stream().filter(entry -> entry.getValue() + .equalsIgnoreCase(capabilityDefinition.getName())) + .collect(Collectors.toList()); + if(capNamesEntries.size() == 1 && capNamesEntries.get(0).getKey() + .equals(capabilityDefinition.getUniqueId())) { + isCapabilityNameUnique = true; + } + } + return Either.left(isCapabilityNameUnique); + } + + private Either isCapabilityNameRegexValid(ResponseFormatManager responseFormatManager, + String capabilityName) { + if (!isValidCapabilityName(capabilityName)) { + LOGGER.error("Capability name {} is invalid, Only alphanumeric chars, underscore and dot allowed", + capabilityName); + ResponseFormat errorResponse = responseFormatManager + .getResponseFormat(ActionStatus.INVALID_CAPABILITY_NAME, capabilityName); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private boolean isValidCapabilityName(String capabilityName) { + return NAME_VALIDATION_REGEX_PATTERN.matcher(capabilityName).matches(); + } + + protected ResponseFormatManager getResponseFormatManager() { + return ResponseFormatManager.getInstance(); + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/RequirementValidation.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/RequirementValidation.java new file mode 100644 index 0000000000..0c6a29415a --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/validation/RequirementValidation.java @@ -0,0 +1,272 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.components.validation; + +import fj.data.Either; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; +import org.openecomp.sdc.be.components.impl.ResponseFormatManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Component("requirementValidation") +public class RequirementValidation { + + private static final Logger LOGGER = LoggerFactory.getLogger(RequirementValidation.class); + private static final String REQUIREMENT_NOT_FOUND_IN_COMPONENT = "Requirement not found in component {} "; + private static final Pattern NAME_VALIDATION_REGEX_PATTERN = Pattern.compile("^[a-zA-Z0-9_.]*$"); + + public Either validateRequirements( + Collection requirements, + org.openecomp.sdc.be.model.Component component, boolean isUpdate) { + + for(RequirementDefinition requirementDefinition : requirements) { + Either requirementValidationResponse + = validateRequirement(requirementDefinition, component, isUpdate); + if (requirementValidationResponse.isRight()) { + return requirementValidationResponse; + } + } + return Either.left(Boolean.TRUE); + } + + private Either validateRequirement( + RequirementDefinition requirementDefinition, + org.openecomp.sdc.be.model.Component component, + boolean isUpdate) { + ResponseFormatManager responseFormatManager = getResponseFormatManager(); + if(isUpdate) { + Either requirementExistValidationEither + = isRequirementExist(requirementDefinition, responseFormatManager, component); + if (requirementExistValidationEither.isRight()) { + return Either.right(requirementExistValidationEither.right().value()); + } + } + + Either requirementNameValidationResponse + = isRequirementNameValid(requirementDefinition, responseFormatManager, + component, isUpdate); + if (requirementNameValidationResponse.isRight()) { + return Either.right(requirementNameValidationResponse.right().value()); + } + + Either requirementTypeEmptyEither = + isRequirementCapabilityEmpty(responseFormatManager, + requirementDefinition.getCapability()); + if (requirementTypeEmptyEither.isRight()) { + return Either.right(requirementTypeEmptyEither.right().value()); + } + Either requirementOccurrencesValidationEither = + validateOccurrences(requirementDefinition, responseFormatManager); + if (requirementOccurrencesValidationEither.isRight()) { + return Either.right(requirementOccurrencesValidationEither.right().value()); + } + return Either.left(Boolean.TRUE); + } + + private Either validateOccurrences(RequirementDefinition requirementDefinition, + ResponseFormatManager responseFormatManager) { + String maxOccurrences = requirementDefinition.getMaxOccurrences(); + String minOccurrences = requirementDefinition.getMinOccurrences(); + if(StringUtils.isNotEmpty(maxOccurrences) && StringUtils.isNotEmpty(minOccurrences)) { + Either requirementOccurrencesValidationEither = + validateOccurrences(responseFormatManager, minOccurrences, + maxOccurrences); + if (requirementOccurrencesValidationEither.isRight()) { + return Either.right(requirementOccurrencesValidationEither.right().value()); + } + } + return Either.left(Boolean.TRUE); + } + + private Either isRequirementNameValid( + RequirementDefinition requirementDefinition, + ResponseFormatManager responseFormatManager, + org.openecomp.sdc.be.model.Component component, boolean isUpdate) { + Either requirementNameEmptyEither = + isRequirementNameEmpty(responseFormatManager, requirementDefinition.getName()); + if (requirementNameEmptyEither.isRight()) { + return Either.right(requirementNameEmptyEither.right().value()); + } + + Either requirementNameRegexValidationResponse = + isRequirementNameRegexValid(responseFormatManager, requirementDefinition.getName()); + if (requirementNameRegexValidationResponse.isRight()) { + return Either.right(requirementNameRegexValidationResponse.right().value()); + } + + Either requirementNameUniqueResponse + = validateRequirementNameUnique(requirementDefinition, + component, isUpdate ); + if(requirementNameUniqueResponse.isRight()) { + return Either.right(requirementNameUniqueResponse.right().value()); + } + if (!requirementNameUniqueResponse.left().value()) { + LOGGER.error("Requirement name {} already in use ", requirementDefinition.getName()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .REQUIREMENT_NAME_ALREADY_IN_USE, requirementDefinition.getName()); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either isRequirementNameEmpty( + ResponseFormatManager responseFormatManager, + String requirementName) { + if (StringUtils.isEmpty(requirementName)) { + LOGGER.error("Requirement Name is mandatory"); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .REQUIREMENT_NAME_MANDATORY); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either validateOccurrences ( + ResponseFormatManager responseFormatManager, + String minOccurrences, String maxOccurrences ) { + if(StringUtils.isNotEmpty(maxOccurrences)&& "UNBOUNDED".equalsIgnoreCase(maxOccurrences) + && Integer.parseInt(minOccurrences) >= 0) { + return Either.left(Boolean.TRUE); + } else if(Integer.parseInt(minOccurrences) < 0) { + LOGGER.debug("Invalid occurrences format.low_bound occurrence negative {}", minOccurrences); + ResponseFormat responseFormat = responseFormatManager.getResponseFormat(ActionStatus.INVALID_OCCURRENCES); + return Either.right(responseFormat); + } + else if(Integer.parseInt(maxOccurrences) < Integer.parseInt(minOccurrences)){ + LOGGER.error("Requirement maxOccurrences should be greater than minOccurrences"); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .MAX_OCCURRENCES_SHOULD_BE_GREATER_THAN_MIN_OCCURRENCES); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + private Either isRequirementCapabilityEmpty( + ResponseFormatManager responseFormatManager, + String requirementCapability) { + if (StringUtils.isEmpty(requirementCapability)) { + LOGGER.error("Requirement capability is mandatory"); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .REQUIREMENT_CAPABILITY_MANDATORY); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either validateRequirementNameUnique( + RequirementDefinition requirementDefinition, + org.openecomp.sdc.be.model.Component component, + boolean isUpdate) { + boolean isRequirementNameUnique = false; + + Map> componentRequirements = component.getRequirements(); + if(MapUtils.isEmpty(componentRequirements)){ + return Either.left(true); + } + List requirementDefinitionList = componentRequirements.values() + .stream().flatMap(Collection::stream).collect(Collectors.toList()); + + if(CollectionUtils.isEmpty(requirementDefinitionList)){ + return Either.left(true); + } + + Map requirementNameMap = new HashMap<>(); + requirementDefinitionList.forEach(requirement -> requirementNameMap + .put(requirement.getUniqueId(), requirement.getName())); + + if (!requirementNameMap.values().contains(requirementDefinition.getName())){ + isRequirementNameUnique = true; + } + if (!isRequirementNameUnique && isUpdate){ + List> reqNamesEntry = requirementNameMap.entrySet() + .stream().filter(entry -> entry.getValue().equalsIgnoreCase(requirementDefinition.getName())) + .collect(Collectors.toList()); + if(reqNamesEntry.size() == 1 && reqNamesEntry.get(0).getKey() + .equals(requirementDefinition.getUniqueId())) { + isRequirementNameUnique = true; + } + } + return Either.left(isRequirementNameUnique); + } + + private Either isRequirementExist( + RequirementDefinition definition, + ResponseFormatManager responseFormatManager, + org.openecomp.sdc.be.model.Component component) { + Map> componentRequirements = component.getRequirements(); + if(MapUtils.isEmpty(componentRequirements)){ + LOGGER.error(REQUIREMENT_NOT_FOUND_IN_COMPONENT, component.getUniqueId()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .REQUIREMENT_NOT_FOUND, component.getUniqueId()); + return Either.right(errorResponse); + } + + List requirementDefinitionList = componentRequirements.values() + .stream().flatMap(Collection::stream).collect(Collectors.toList()); + if(CollectionUtils.isEmpty(requirementDefinitionList)){ + LOGGER.error(REQUIREMENT_NOT_FOUND_IN_COMPONENT, component.getUniqueId()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .REQUIREMENT_NOT_FOUND, component.getUniqueId()); + return Either.right(errorResponse); + } + boolean isRequirementExist = requirementDefinitionList.stream() + .anyMatch(requirementDefinition -> requirementDefinition.getUniqueId() + .equalsIgnoreCase(definition.getUniqueId())); + + if(!isRequirementExist) { + LOGGER.error(REQUIREMENT_NOT_FOUND_IN_COMPONENT, component.getUniqueId()); + ResponseFormat errorResponse = responseFormatManager.getResponseFormat(ActionStatus + .REQUIREMENT_NOT_FOUND, component.getUniqueId()); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private Either isRequirementNameRegexValid(ResponseFormatManager responseFormatManager, + String requirementName) { + if (!isValidRequirementName(requirementName)) { + LOGGER.error("Requirement name {} is invalid, Only alphanumeric chars, underscore and dot allowed", + requirementName); + ResponseFormat errorResponse = responseFormatManager + .getResponseFormat(ActionStatus.INVALID_REQUIREMENT_NAME, requirementName); + return Either.right(errorResponse); + } + return Either.left(Boolean.TRUE); + } + + private boolean isValidRequirementName(String requirementName) { + return NAME_VALIDATION_REGEX_PATTERN.matcher(requirementName).matches(); + } + + protected ResponseFormatManager getResponseFormatManager() { + return ResponseFormatManager.getInstance(); + } + +} + diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java index 909d4da994..0930daad04 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java @@ -1522,5 +1522,32 @@ public class ComponentsUtils { } return getResponseFormat(exception.getActionStatus(), exception.getParams()); } + public ActionStatus convertFromStorageResponseForRelationshipType( + StorageOperationStatus storageResponse) { + ActionStatus responseEnum; + switch (storageResponse) { + case OK: + responseEnum = ActionStatus.OK; + break; + case CONNECTION_FAILURE: + case GRAPH_IS_LOCK: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + case BAD_REQUEST: + responseEnum = ActionStatus.INVALID_CONTENT; + break; + case ENTITY_ALREADY_EXISTS: + responseEnum = ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST; + break; + case SCHEMA_VIOLATION: + responseEnum = ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST; + break; + default: + responseEnum = ActionStatus.GENERAL_ERROR; + break; + } + log.debug(CONVERT_STORAGE_RESPONSE_TO_ACTION_RESPONSE, storageResponse, responseEnum); + return responseEnum; + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java index c321df1449..d27db55158 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/BeGenericServlet.java @@ -148,6 +148,16 @@ public class BeGenericServlet extends BasicServlet { return getClassFromWebAppContext(context, () -> InterfaceOperationBusinessLogic.class); } + protected CapabilitiesBusinessLogic getCapabilitiesBL(ServletContext context) { + return getClassFromWebAppContext(context, () -> CapabilitiesBusinessLogic.class); + } + + protected RelationshipTypeBusinessLogic getRelationshipTypeBL(ServletContext context) { + return getClassFromWebAppContext(context, () -> RelationshipTypeBusinessLogic.class); + } + protected RequirementBusinessLogic getRequirementBL(ServletContext context) { + return getClassFromWebAppContext(context, () -> RequirementBusinessLogic.class); + } ComponentsCleanBusinessLogic getComponentCleanerBL(ServletContext context) { return getClassFromWebAppContext(context, () -> ComponentsCleanBusinessLogic.class); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/CapabilityServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/CapabilityServlet.java new file mode 100644 index 0000000000..a1456bb65d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/CapabilityServlet.java @@ -0,0 +1,320 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.servlets; + +import com.jcabi.aspects.Loggable; +import fj.data.Either; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.openecomp.sdc.be.components.impl.CapabilitiesBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.CapabilityDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.log.wrappers.Logger; +import org.openecomp.sdc.exception.ResponseFormat; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; +import java.util.Optional; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Api(value = "Capability Servlet", description = "Capability Servlet") +@Singleton +public class CapabilityServlet extends AbstractValidationsServlet { + private static final Logger LOGGER = Logger.getLogger(CapabilityServlet.class); + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/capabilities") + @ApiOperation(value = "Create Capabilities on resource", httpMethod = "POST", + notes = "Create Capabilities on resource", response = Response.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Create Capabilities"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Capability already exist")}) + public Response createCapabilitiesOnResource( + @ApiParam(value = "Capability to create", required = true) String data, + @ApiParam(value = "Resource Id") @PathParam("resourceId") String resourceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "resources" , resourceId, + request, userId, false, "createCapabilities"); + } + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/capabilities") + @ApiOperation(value = "Update Capabilities on resource", httpMethod = "PUT", + notes = "Update Capabilities on resource", response = CapabilityDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Update Capabilities"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response updateCapabilitiesOnResource( + @ApiParam(value = "Capabilities to update", required = true) String data, + @ApiParam(value = "Component Id") @PathParam("resourceId") String resourceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "resources", resourceId, + request, userId, true, "updateCapabilities"); + } + + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/capabilities/{capabilityId}") + @ApiOperation(value = "Get Capability from resource", httpMethod = "GET", + notes = "GET Capability from resource", response = CapabilityDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "GET Capability"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response getCapabilityOnResource( + @ApiParam(value = "Resource Id") @PathParam("resourceId") String resourceId, + @ApiParam(value = "Capability Id") @PathParam("capabilityId") String capabilityId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return get(capabilityId, resourceId, request, userId); + } + + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/capabilities/{capabilityId}") + @ApiOperation(value = "Delete capability from resource", httpMethod = "DELETE", + notes = "Delete capability from resource", response = CapabilityDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Delete capability"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response deleteCapabilityOnResource( + @ApiParam(value = "capability Id") @PathParam("capabilityId") String capabilityId, + @ApiParam(value = "Resource Id") @PathParam("resourceId") String resourceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return delete(capabilityId, resourceId, request, userId); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/capabilities") + @ApiOperation(value = "Create Capabilities on service", httpMethod = "POST", + notes = "Create Capabilities on service", response = Response.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Create Capabilities"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Capability already exist")}) + public Response createCapabilitiesOnService( + @ApiParam(value = "Capability to create", required = true) String data, + @ApiParam(value = "Service Id") @PathParam("serviceId") String serviceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "services" , serviceId, + request, userId, false, "createCapabilities"); + } + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/capabilities") + @ApiOperation(value = "Update Capabilities on service", httpMethod = "PUT", + notes = "Update Capabilities on service", response = CapabilityDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Update Capabilities"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response updateCapabilitiesOnService( + @ApiParam(value = "Capabilities to update", required = true) String data, + @ApiParam(value = "Component Id") @PathParam("serviceId") String serviceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "services", serviceId, + request, userId, true, "updateCapabilities"); + } + + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/capabilities/{capabilityId}") + @ApiOperation(value = "Get Capability from service", httpMethod = "GET", + notes = "GET Capability from service", response = CapabilityDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "GET Capability"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response getCapabilityOnService( + @ApiParam(value = "Service Id") @PathParam("serviceId") String serviceId, + @ApiParam(value = "Capability Id") @PathParam("capabilityId") String capabilityId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return get(capabilityId, serviceId, request, userId); + } + + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/capabilities/{capabilityId}") + @ApiOperation(value = "Delete capability from service", httpMethod = "DELETE", + notes = "Delete capability from service", response = CapabilityDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Delete capability"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response deleteCapabilityOnService( + @ApiParam(value = "capability Id") @PathParam("capabilityId") String capabilityId, + @ApiParam(value = "Service Id") @PathParam("serviceId") String serviceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return delete(capabilityId, serviceId, request, userId); + } + + private Response createOrUpdate (String data, String componentType, String componentId, + HttpServletRequest request, + String userId, + boolean isUpdate, + String errorContext) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + + User modifier = new User(); + modifier.setUserId(userId); + LOGGER.debug("Start create or update request of {} with modifier id {}", url, userId); + try { + String componentIdLower = componentId.toLowerCase(); + CapabilitiesBusinessLogic businessLogic = getCapabilitiesBL(context); + + Either, ResponseFormat> mappedCapabilitiesDataEither + = getMappedCapabilitiesData(data, modifier, ComponentTypeEnum.findByParamName(componentType)); + if(mappedCapabilitiesDataEither.isRight()) { + LOGGER.error("Failed to create or update capabilities"); + buildErrorResponse(mappedCapabilitiesDataEither.right().value()); + } + List mappedCapabilitiesData = mappedCapabilitiesDataEither.left().value(); + Either, ResponseFormat> actionResponse; + if(isUpdate) { + actionResponse = businessLogic.updateCapabilities(componentIdLower, + mappedCapabilitiesData, modifier, errorContext, true); + } else { + actionResponse = businessLogic.createCapabilities(componentIdLower, + mappedCapabilitiesData, modifier, errorContext, true); + } + if (actionResponse.isRight()) { + LOGGER.error("Failed to create or update capabilities"); + return buildErrorResponse(actionResponse.right().value()); + } + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), + actionResponse.left().value()); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Capabilities create or update"); + LOGGER.error("Failed to create or update capabilities with an error", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Response get (String capabilityIdToGet, String componentId, + HttpServletRequest request, String userId){ + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + + User modifier = new User(); + modifier.setUserId(userId); + LOGGER.debug("Start get request of {} with modifier id {}", url, userId); + + try { + String componentIdLower = componentId.toLowerCase(); + CapabilitiesBusinessLogic businessLogic = getCapabilitiesBL(context); + + Either actionResponse = businessLogic + .getCapability(componentIdLower, capabilityIdToGet, modifier, true); + if (actionResponse.isRight()) { + LOGGER.error("failed to get capability"); + return buildErrorResponse(actionResponse.right().value()); + } + Object result = RepresentationUtils.toFilteredRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get capability"); + LOGGER.error("get capabilities failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Response delete (String capabilityId, String componentId, HttpServletRequest + request, String userId){ + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + + User modifier = new User(); + modifier.setUserId(userId); + LOGGER.debug("Start delete request of {} with modifier id {}", url, userId); + + try { + String componentIdLower = componentId.toLowerCase(); + CapabilitiesBusinessLogic businessLogic = getCapabilitiesBL(context); + + Either actionResponse = businessLogic + .deleteCapability(componentIdLower, capabilityId, modifier, true); + if (actionResponse.isRight()) { + LOGGER.error("failed to delete capability"); + return buildErrorResponse(actionResponse.right().value()); + } + Object result = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete capability"); + LOGGER.error("Delete capability failed with an error", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Either, ResponseFormat> getMappedCapabilitiesData(String inputJson, User user, + ComponentTypeEnum componentTypeEnum){ + Either mappedData = getComponentsUtils() + .convertJsonToObjectUsingObjectMapper(inputJson, user, UiComponentDataTransfer.class, + AuditingActionEnum.CREATE_RESOURCE, componentTypeEnum); + Optional> capabilityDefinitionList = + mappedData.left().value().getCapabilities().values().stream().findFirst(); + return capabilityDefinitionList., ResponseFormat>> + map(Either::left).orElseGet(() -> Either.right(getComponentsUtils() + .getResponseFormat(ActionStatus.GENERAL_ERROR))); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RequirementServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RequirementServlet.java new file mode 100644 index 0000000000..51f6783f0d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/RequirementServlet.java @@ -0,0 +1,325 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.servlets; + +import com.jcabi.aspects.Loggable; +import fj.data.Either; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.openecomp.sdc.be.components.impl.RequirementBusinessLogic; +import org.openecomp.sdc.be.config.BeEcompErrorManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.ui.model.UiComponentDataTransfer; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.log.wrappers.Logger; +import org.openecomp.sdc.exception.ResponseFormat; + +import javax.inject.Singleton; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.util.List; +import java.util.Optional; + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Consumes(MediaType.APPLICATION_JSON) +@Produces(MediaType.APPLICATION_JSON) +@Api(value = "Requirement Servlet", description = "Requirement Servlet") +@Singleton +public class RequirementServlet extends AbstractValidationsServlet { + private static final Logger LOGGER = Logger.getLogger(RequirementServlet.class); + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/requirements") + @ApiOperation(value = "Create requirements on resource", httpMethod = "POST", + notes = "Create requirements on resource", response = Response.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Create requirements"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "requirement already exist")}) + public Response createRequirementsOnResource( + @ApiParam(value = "Requirement to create", required = true) String data, + @ApiParam(value = "Resource Id") @PathParam("resourceId") String resourceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "resources" , resourceId, request, + userId, false, "createRequirements"); + } + + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/requirements") + @ApiOperation(value = "Update Requirements on resource", httpMethod = "PUT", + notes = "Update Requirements on resource", response = RequirementDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Update Requirements"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response updateRequirementsOnResource( + @ApiParam(value = "Requirements to update", required = true) String data, + @ApiParam(value = "Component Id") @PathParam("resourceId") String resourceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "resources", resourceId, request, + userId, true, "updateRequirements"); + } + + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/requirements/{requirementId}") + @ApiOperation(value = "Get Requirement from resource", httpMethod = "GET", + notes = "GET Requirement from resource", response = RequirementDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "GET requirement"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response getRequirementsFromResource( + @ApiParam(value = "Resource Id") @PathParam("resourceId") String resourceId, + @ApiParam(value = "Requirement Id") @PathParam("requirementId") String requirementId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return get(requirementId, resourceId, request, userId); + } + + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/resources/{resourceId}/requirements/{requirementId}") + @ApiOperation(value = "Delete requirements from resource", httpMethod = "DELETE", + notes = "Delete requirements from resource", response = RequirementDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Delete requirement"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response deleteRequirementsFromResource( + @ApiParam(value = "Resource Id") @PathParam("resourceId") String resourceId, + @ApiParam(value = "requirement Id") @PathParam("requirementId") String requirementId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return delete(requirementId, resourceId, request, userId); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/requirements") + @ApiOperation(value = "Create requirements on service", httpMethod = "POST", + notes = "Create requirements on service", response = Response.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Create Requirements"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Requirement already exist")}) + public Response createRequirementsOnService( + @ApiParam(value = "Requirements to create", required = true) String data, + @ApiParam(value = "Service Id") @PathParam("serviceId") String serviceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "services" , serviceId, request, userId, + false , "createRequirements"); + } + + + @PUT + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/requirements") + @ApiOperation(value = "Update requirements on service", httpMethod = "PUT", + notes = "Update requirements on service", response = RequirementDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Update requirements"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response updateRequirementsOnService( + @ApiParam(value = "Requirements to update", required = true) String data, + @ApiParam(value = "Component Id") @PathParam("serviceId") String serviceId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return createOrUpdate(data, "services", serviceId, request, userId, + true, "updateRequirements"); + } + + @GET + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/requirements/{requirementId}") + @ApiOperation(value = "Get requirement from service", httpMethod = "GET", + notes = "GET requirement from service", response = RequirementDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "GET Requirements"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response getRequirementsOnService( + @ApiParam(value = "Service Id") @PathParam("serviceId") String serviceId, + @ApiParam(value = "Requirement Id") @PathParam("requirementId") String requirementId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + + return get(requirementId, serviceId, request, userId); + } + + + @DELETE + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Path("/services/{serviceId}/requirements/{requirementId}") + @ApiOperation(value = "Delete requirement from service", httpMethod = "DELETE", + notes = "Delete requirement from service", response = RequirementDefinition.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Delete Requirements"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content")}) + public Response deleteRequirementsOnService( + @ApiParam(value = "Service Id") @PathParam("serviceId") String serviceId, + @ApiParam(value = "Requirement Id") @PathParam("requirementId") String requirementId, + @Context final HttpServletRequest request, + @HeaderParam(value = Constants.USER_ID_HEADER) String userId) { + return delete(requirementId, serviceId, request, userId); + } + + + private Response createOrUpdate (String data, String componentType, String componentId, + HttpServletRequest request, String userId, + boolean isUpdate, String errorContext) { + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + + User modifier = new User(); + modifier.setUserId(userId); + LOGGER.debug("Start create or update request of {} with modifier id {}", url, userId); + + try { + String componentIdLower = componentId.toLowerCase(); + RequirementBusinessLogic businessLogic = getRequirementBL(context); + + Either, ResponseFormat> mappedRequirementDataEither = + getMappedRequirementData(data, modifier, ComponentTypeEnum.findByParamName(componentType)); + if(mappedRequirementDataEither.isRight()) { + LOGGER.error("Failed to create or update requirements"); + return buildErrorResponse(mappedRequirementDataEither.right().value()); + } + List mappedRequirementData = mappedRequirementDataEither.left().value(); + Either, ResponseFormat> actionResponse; + if(isUpdate) { + actionResponse = businessLogic.updateRequirements(componentIdLower, mappedRequirementData, modifier, + errorContext, true); + } else { + actionResponse = businessLogic.createRequirements(componentIdLower, mappedRequirementData, modifier, + errorContext, true); + } + + if (actionResponse.isRight()) { + LOGGER.error("Failed to create or update requirements"); + return buildErrorResponse(actionResponse.right().value()); + } + + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), + actionResponse.left().value()); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("requirements create or update"); + LOGGER.error("Failed to create or update requirements with an error", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Response get (String requirementIdToGet, String componentId, + HttpServletRequest request, String userId){ + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + + User modifier = new User(); + modifier.setUserId(userId); + LOGGER.debug("Start get request of {} with modifier id {}", url, userId); + + try { + String componentIdLower = componentId.toLowerCase(); + RequirementBusinessLogic businessLogic = getRequirementBL(context); + + Either actionResponse = businessLogic + .getRequirement(componentIdLower, requirementIdToGet, modifier, true); + if (actionResponse.isRight()) { + LOGGER.error("failed to get requirements"); + return buildErrorResponse(actionResponse.right().value()); + } + Object result = RepresentationUtils.toFilteredRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get requirements"); + LOGGER.error("get requirements failed with exception", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Response delete (String requirementId, String componentId, HttpServletRequest + request, String userId){ + + ServletContext context = request.getSession().getServletContext(); + String url = request.getMethod() + " " + request.getRequestURI(); + + User modifier = new User(); + modifier.setUserId(userId); + LOGGER.debug("Start delete request of {} with modifier id {}", url, userId); + + try { + String componentIdLower = componentId.toLowerCase(); + RequirementBusinessLogic businessLogic = getRequirementBL(context); + + Either actionResponse = businessLogic + .deleteRequirement(componentIdLower, requirementId, modifier, true); + if (actionResponse.isRight()) { + LOGGER.error("failed to delete requirements"); + return buildErrorResponse(actionResponse.right().value()); + } + Object result = RepresentationUtils.toRepresentation(actionResponse.left().value()); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Delete requirements"); + LOGGER.error("Delete requirements failed with an error", e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + + private Either, ResponseFormat> getMappedRequirementData(String inputJson, User user, + ComponentTypeEnum componentTypeEnum){ + Either mappedData = getComponentsUtils() + .convertJsonToObjectUsingObjectMapper(inputJson, user, UiComponentDataTransfer.class, + AuditingActionEnum.CREATE_RESOURCE, componentTypeEnum); + Optional> requirementDefinitionList = mappedData.left().value() + .getRequirements().values().stream().findFirst(); + return requirementDefinitionList., ResponseFormat>> + map(Either::left).orElseGet(() -> Either.right(getComponentsUtils() + .getResponseFormat(ActionStatus.GENERAL_ERROR))); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java index 00b04a4ffc..459629ff26 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesFetchServlet.java @@ -26,28 +26,44 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; +import org.apache.commons.collections4.ListUtils; +import org.openecomp.sdc.be.components.impl.CapabilitiesBusinessLogic; +import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic; import org.openecomp.sdc.be.components.impl.InterfaceOperationBusinessLogic; import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; +import org.openecomp.sdc.be.components.impl.RelationshipTypeBusinessLogic; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.impl.WebAppContextWrapper; +import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; +import org.openecomp.sdc.be.datatypes.components.ResourceMetadataDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.model.CapabilityTypeDefinition; +import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.RelationshipTypeDefinition; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.common.datastructure.Wrapper; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; -import org.springframework.web.context.WebApplicationContext; import javax.inject.Singleton; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.stream.Collectors; + @Loggable(prepend = true, value = Loggable.DEBUG, trim = false) @Path("/v1/catalog") @@ -56,6 +72,7 @@ import java.util.Map; public class TypesFetchServlet extends AbstractValidationsServlet { private static final Logger log = Logger.getLogger(TypesFetchServlet.class); + private static final String FAILED_TO_GET_ALL_NON_ABSTRACT = "failed to get all non abstract {}"; @GET @Path("dataTypes") @@ -154,4 +171,188 @@ public class TypesFetchServlet extends AbstractValidationsServlet { return buildErrorResponse(responseFormat); } } + @GET + @Path("capabilityTypes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get capability types", httpMethod = "GET", notes = "Returns capability types", response = + Response.class) + @ApiResponses(value = {@ApiResponse(code = 200, message = "capabilityTypes"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Capability types not found")}) + public Response getAllCapabilityTypesServlet(@Context final HttpServletRequest request, @HeaderParam(value = + Constants.USER_ID_HEADER) String userId) { + + Wrapper responseWrapper = new Wrapper<>(); + Wrapper userWrapper = new Wrapper<>(); + ServletContext context = request.getSession().getServletContext(); + + try { + init(); + validateUserExist(responseWrapper, userWrapper, userId); + + if (responseWrapper.isEmpty()) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} | modifier id is {}", url, userId); + + CapabilitiesBusinessLogic businessLogic = getCapabilitiesBL(context); + Either, ResponseFormat> allDataTypes = + businessLogic.getAllCapabilityTypes(); + + if (allDataTypes.isRight()) { + log.info("Failed to get all capability types. Reason - {}", allDataTypes.right().value()); + Response errorResponse = buildErrorResponse(allDataTypes.right().value()); + responseWrapper.setInnerElement(errorResponse); + + } else { + + Map dataTypes = allDataTypes.left().value(); + String dataTypeJson = gson.toJson(dataTypes); + Response okResponse = + buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), dataTypeJson); + responseWrapper.setInnerElement(okResponse); + + } + } + + return responseWrapper.getInnerElement(); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Capability Types"); + log.debug("get all capability types failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + + @GET + @Path("relationshipTypes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get relationship types", httpMethod = "GET", notes = "Returns relationship types", response = + Response.class) + @ApiResponses(value = {@ApiResponse(code = 200, message = "relationshipTypes"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Relationship types not found")}) + public Response getAllRelationshipTypesServlet(@Context final HttpServletRequest request, @HeaderParam(value = + Constants.USER_ID_HEADER) String userId) { + + Wrapper responseWrapper = new Wrapper<>(); + Wrapper userWrapper = new Wrapper<>(); + ServletContext context = request.getSession().getServletContext(); + + try { + init(); + validateUserExist(responseWrapper, userWrapper, userId); + + if (responseWrapper.isEmpty()) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} | modifier id is {}", url, userId); + + RelationshipTypeBusinessLogic businessLogic = getRelationshipTypeBL(context); + Either, ResponseFormat> allDataTypes = + businessLogic.getAllRelationshipTypes(); + + if (allDataTypes.isRight()) { + log.info("Failed to get all relationship types. Reason - {}", allDataTypes.right().value()); + Response errorResponse = buildErrorResponse(allDataTypes.right().value()); + responseWrapper.setInnerElement(errorResponse); + + } else { + + Map dataTypes = allDataTypes.left().value(); + String dataTypeJson = gson.toJson(dataTypes); + Response okResponse = + buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), dataTypeJson); + responseWrapper.setInnerElement(okResponse); + + } + } + + return responseWrapper.getInnerElement(); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Relationship Types"); + log.debug("get all relationship types failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + + @GET + @Path("nodeTypes") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @ApiOperation(value = "Get node types", httpMethod = "GET", notes = "Returns node types", response = Response.class) + @ApiResponses(value = {@ApiResponse(code = 200, message = "nodeTypes"), @ApiResponse(code = 403, message = + "Restricted operation"), @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 404, message = "Node types not found")}) + public Response getAllNodeTypesServlet(@Context final HttpServletRequest request, @HeaderParam(value = + Constants.USER_ID_HEADER) String userId) { + + Wrapper responseWrapper = new Wrapper<>(); + Wrapper userWrapper = new Wrapper<>(); + ServletContext context = request.getSession().getServletContext(); + Either, Response> response; + Map componentMap; + + try { + init(); + validateUserExist(responseWrapper, userWrapper, userId); + + if (responseWrapper.isEmpty()) { + String url = request.getMethod() + " " + request.getRequestURI(); + log.debug("Start handle request of {} | modifier id is {}", url, userId); + + ComponentBusinessLogic resourceBL = getComponentBL(ComponentTypeEnum.RESOURCE, context); + response = getComponent(resourceBL, true, userId); + if (response.isRight()) { + return response.right().value(); + } + componentMap = new HashMap<>(response.left().value()); + + response = getComponent(resourceBL, false, userId); + if (response.isRight()) { + return response.right().value(); + } + componentMap.putAll(response.left().value()); + + String nodeTypesJson = gson.toJson(componentMap); + Response okResponse = + buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), nodeTypesJson); + responseWrapper.setInnerElement(okResponse); + } + + return responseWrapper.getInnerElement(); + } catch (Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Node Types"); + log.debug("get all node types failed with exception", e); + ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR); + return buildErrorResponse(responseFormat); + } + } + + private Either, Response> getComponent(ComponentBusinessLogic resourceBL, boolean isAbstract, + String userId) { + Either, ResponseFormat> actionResponse; + List componentList; + + actionResponse = + resourceBL.getLatestVersionNotAbstractComponentsMetadata(isAbstract, HighestFilterEnum.HIGHEST_ONLY + , ComponentTypeEnum.RESOURCE, null, userId); + if (actionResponse.isRight()) { + log.debug(FAILED_TO_GET_ALL_NON_ABSTRACT, ComponentTypeEnum.RESOURCE.getValue()); + return Either.right(buildErrorResponse(actionResponse.right().value())); + } + + componentList = actionResponse.left().value(); + + return Either.left(ListUtils.emptyIfNull(componentList).stream() + .filter(component -> ((ResourceMetadataDataDefinition) component + .getComponentMetadataDefinition().getMetadataDataDefinition()).getToscaResourceName() != null) + .collect(Collectors.toMap( + component -> ((ResourceMetadataDataDefinition) component + .getComponentMetadataDefinition().getMetadataDataDefinition()).getToscaResourceName(), + component -> component, (component1, component2) -> component1))); + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java index a09e34fa9a..8ecda2ce61 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/TypesUploadServlet.java @@ -34,6 +34,7 @@ import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.GroupTypeDefinition; import org.openecomp.sdc.be.model.PolicyTypeDefinition; +import org.openecomp.sdc.be.model.RelationshipTypeDefinition; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata; import org.openecomp.sdc.common.api.Constants; @@ -72,15 +73,18 @@ public class TypesUploadServlet extends AbstractValidationsServlet { private final DataTypeImportManager dataTypeImportManager; private final GroupTypeImportManager groupTypeImportManager; private final PolicyTypeImportManager policyTypeImportManager; + private final RelationshipTypeImportManager relationshipTypeImportManager; public TypesUploadServlet(CapabilityTypeImportManager capabilityTypeImportManager, InterfaceLifecycleTypeImportManager interfaceLifecycleTypeImportManager, CategoriesImportManager categoriesImportManager, DataTypeImportManager dataTypeImportManager, - GroupTypeImportManager groupTypeImportManager, PolicyTypeImportManager policyTypeImportManager) { + GroupTypeImportManager groupTypeImportManager, PolicyTypeImportManager policyTypeImportManager, + RelationshipTypeImportManager relationshipTypeImportManager) { this.capabilityTypeImportManager = capabilityTypeImportManager; this.interfaceLifecycleTypeImportManager = interfaceLifecycleTypeImportManager; this.categoriesImportManager = categoriesImportManager; this.dataTypeImportManager = dataTypeImportManager; this.groupTypeImportManager = groupTypeImportManager; this.policyTypeImportManager = policyTypeImportManager; + this.relationshipTypeImportManager = relationshipTypeImportManager; } @POST @@ -93,6 +97,21 @@ public class TypesUploadServlet extends AbstractValidationsServlet { return uploadElementTypeServletLogic(createElementsMethod, file, request, creator, NodeTypeEnum.CapabilityType.name()); } + @POST + @Path("/relationship") + @ApiOperation(value = "Create Relationship Type from yaml", httpMethod = "POST", + notes = "Returns created Relationship Type", response = Response.class) + @ApiResponses(value = {@ApiResponse(code = 201, message = "Relationship Type created"), + @ApiResponse(code = 403, message = "Restricted operation"), + @ApiResponse(code = 400, message = "Invalid content / Missing content"), + @ApiResponse(code = 409, message = "Relationship Type already exist")}) + public Response uploadRelationshipType(@ApiParam("FileInputStream") @FormDataParam("relationshipTypeZip") File file, + @Context final HttpServletRequest request, + @HeaderParam("USER_ID") String creator) { + return uploadElementTypeServletLogic(this::createRelationshipTypes, file, request, creator, + NodeTypeEnum.RelationshipType.getName()); + } + @POST @Path("/interfaceLifecycle") @ApiOperation(value = "Create Interface Lyfecycle Type from yaml", httpMethod = "POST", notes = "Returns created Interface Lifecycle Type", response = Response.class) @@ -299,6 +318,13 @@ public class TypesUploadServlet extends AbstractValidationsServlet { } } } - + // relationship types + private void createRelationshipTypes(Wrapper responseWrapper, String relationshipTypesYml) { + final Supplier>, ResponseFormat>> + generateElementTypeFromYml = + () -> relationshipTypeImportManager.createRelationshipTypes(relationshipTypesYml); + buildStatusForElementTypeCreate(responseWrapper, generateElementTypeFromYml, + ActionStatus.RELATIONSHIP_TYPE_ALREADY_EXIST, NodeTypeEnum.RelationshipType.name()); + } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java index 04119fed7b..bd797c970b 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CapabilityRequirementConverter.java @@ -258,22 +258,22 @@ public class CapabilityRequirementConverter { private Either, ToscaError> buildAddSubstitutionMappingsCapabilities(Map componentsCache, Component component, Map> capabilities) { - Map toscaRequirements = new HashMap<>(); + Map toscaCapabilities = new HashMap<>(); Either, ToscaError> result = null; for (Map.Entry> entry : capabilities.entrySet()) { Optional failedToAddRequirement = entry.getValue() .stream() - .filter(c->!addEntry(componentsCache, toscaRequirements, component, new SubstitutionEntry(c.getName(), c.getParentName(), ""), c.getPreviousName(), c.getOwnerId(), c.getPath())) + .filter(c->!addEntry(componentsCache, toscaCapabilities, component, new SubstitutionEntry(c.getName(), c.getParentName(), ""), c.getPreviousName(), c.getOwnerId(), c.getPath())) .findAny(); if(failedToAddRequirement.isPresent()){ - logger.debug("Failed to convert capalility {} for substitution mappings section of a tosca template of the component {}. ", + logger.debug("Failed to convert capability {} for substitution mappings section of a tosca template of the component {}. ", failedToAddRequirement.get().getName(), component.getName()); result = Either.right(ToscaError.NODE_TYPE_CAPABILITY_ERROR); } - logger.debug("Finish convert capalilities for the component {}. ", component.getName()); + logger.debug("Finish convert capabilities for the component {}. ", component.getName()); } if(result == null){ - result = Either.left(toscaRequirements); + result = Either.left(toscaCapabilities); } return result; } @@ -284,7 +284,7 @@ public class CapabilityRequirementConverter { return false; } logger.debug("The requirement/capability {} belongs to the component {} ", entry.getFullName(), component.getUniqueId()); - if (entry.getSourceName() != null) { + if (StringUtils.isNotEmpty(entry.getSourceName())) { addEntry(capReqMap, component, path, entry); } logger.debug("Finish convert the requirement/capability {} for the component {}. ", entry.getFullName(), component.getName()); @@ -318,14 +318,15 @@ public class CapabilityRequirementConverter { } } - Optional ci = component.getComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); + Optional ci = + component.safeGetComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); if(!ci.isPresent()){ logger.debug("Failed to find ci in the path is {} component {}", path, component.getUniqueId()); Collections.reverse(path); logger.debug("try to reverse path {} component {}", path, component.getUniqueId()); - ci = component.getComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); + ci = component.safeGetComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); } if(ci.isPresent()){ prefix = buildCapReqNamePrefix(ci.get().getNormalizedName()); @@ -352,10 +353,10 @@ public class CapabilityRequirementConverter { private void addEntry(Map toscaRequirements, Component component, List capPath, SubstitutionEntry entry) { Optional findFirst = component.safeGetComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(Iterables.getLast(capPath))).findFirst(); - if (findFirst.isPresent()) { - entry.setOwner(findFirst.get().getNormalizedName()); + findFirst.ifPresent(componentInstance -> entry.setOwner(componentInstance.getName())); + if (StringUtils.isNotEmpty(entry.getOwner()) && StringUtils.isNotEmpty(entry.getSourceName())) { + toscaRequirements.put(entry.getFullName(), new String[] { entry.getOwner(), entry.getSourceName() }); } - toscaRequirements.put(entry.getFullName(), new String[] { entry.getOwner(), entry.getSourceName() }); } public Either buildSubstitutedName(Map componentsCache, String name, String previousName, List path, String ownerId, ComponentInstance instance) { @@ -469,31 +470,9 @@ public class CapabilityRequirementConverter { return buildCapReqNamePerOwnerByPath(componentsCache, component, c.getName(), c.getPreviousName(), c.getPath()); } - private void convertProxyCapability(Map toscaCapabilities, CapabilityDefinition c, Map dataTypes, String capabilityName) { - ToscaCapability toscaCapability = new ToscaCapability(); - toscaCapability.setDescription(c.getDescription()); - toscaCapability.setType(c.getType()); - - List occurrences = new ArrayList<>(); - occurrences.add(Integer.valueOf(c.getMinOccurrences())); - if (c.getMaxOccurrences().equals(CapabilityDataDefinition.MAX_OCCURRENCES)) { - occurrences.add(c.getMaxOccurrences()); - } else { - occurrences.add(Integer.valueOf(c.getMaxOccurrences())); - } - toscaCapability.setOccurrences(occurrences); - - toscaCapability.setValid_source_types(c.getValidSourceTypes()); - List properties = c.getProperties(); - if (isNotEmpty(properties)) { - Map toscaProperties = new HashMap<>(); - for (PropertyDefinition property : properties) { - ToscaProperty toscaProperty = PropertyConvertor.getInstance().convertProperty(dataTypes, property, PropertyConvertor.PropertyType.CAPABILITY); - toscaProperties.put(property.getName(), toscaProperty); - } - toscaCapability.setProperties(toscaProperties); - } - toscaCapabilities.put(capabilityName, toscaCapability); + private void convertProxyCapability(Map toscaCapabilities, CapabilityDefinition c, + Map dataTypes, String capabilityName) { + createToscaCapability(toscaCapabilities, c, dataTypes, capabilityName); } private void convertCapability(Map componentsCache, Component component, Map toscaCapabilities, boolean isNodeType, CapabilityDefinition c, Map dataTypes , String capabilityName) { @@ -502,6 +481,11 @@ public class CapabilityRequirementConverter { name = buildCapNamePerOwnerByPath(componentsCache, c, component); } logger.debug("The capability {} belongs to resource {} ", name, component.getUniqueId()); + createToscaCapability(toscaCapabilities, c, dataTypes, name); + } + + private void createToscaCapability(Map toscaCapabilities, CapabilityDefinition c, + Map dataTypes, String name) { ToscaCapability toscaCapability = new ToscaCapability(); toscaCapability.setDescription(c.getDescription()); toscaCapability.setType(c.getType()); @@ -529,6 +513,9 @@ public class CapabilityRequirementConverter { } private String buildCapReqNamePerOwnerByPath(Map componentsCache, Component component, String name, String previousName, List path) { + if (CollectionUtils.isEmpty(path)) { + return name; + } String ownerId = path.get(path.size() - 1); String prefix; if(CollectionUtils.isNotEmpty(component.getGroups())) { @@ -541,14 +528,14 @@ public class CapabilityRequirementConverter { return name; } } - Optional ci = component.getComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); + Optional ci = component.safeGetComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); if(!ci.isPresent()){ logger.debug("Failed to find ci in the path is {} component {}", path, component.getUniqueId()); Collections.reverse(path); logger.debug("try to reverse path {} component {}", path, component.getUniqueId()); - ci = component.getComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); + ci = component.safeGetComponentInstances().stream().filter(c->c.getUniqueId().equals(Iterables.getLast(path))).findFirst(); } if(ci.isPresent()){ prefix = buildCapReqNamePrefix(ci.get().getNormalizedName()); -- cgit 1.2.3-korg