/*- * ============LICENSE_START======================================================= * SDC * ================================================================================ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * 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. * ============LICENSE_END========================================================= * Modifications copyright (c) 2019 Nokia * ================================================================================ */ package org.openecomp.sdc.be.components.impl; import static java.util.stream.Collectors.toList; import fj.data.Either; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException; import org.openecomp.sdc.be.components.impl.model.ToscaTypeImportData; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.elements.ToscaTypeDataDefinition; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; import org.openecomp.sdc.be.impl.ComponentsUtils; import org.openecomp.sdc.be.model.CapabilityTypeDefinition; 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.PropertyDefinition; import org.openecomp.sdc.be.model.normatives.ElementTypeEnum; import org.openecomp.sdc.be.model.normatives.ToscaTypeMetadata; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.api.TypeOperations; import org.openecomp.sdc.be.model.operations.impl.ModelOperation; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.yaml.snakeyaml.Yaml; @Component("commonImportManager") public class CommonImportManager { private static final Logger log = Logger.getLogger(CommonImportManager.class.getName()); private final ComponentsUtils componentsUtils; private final PropertyOperation propertyOperation; private final ModelOperation modelOperation; @Autowired public CommonImportManager(final ComponentsUtils componentsUtils, final PropertyOperation propertyOperation, final ModelOperation modelOperation) { this.componentsUtils = componentsUtils; this.propertyOperation = propertyOperation; this.modelOperation = modelOperation; } public static void setProperties(Map toscaJson, Consumer> consumer) { consumer.accept(getProperties(toscaJson)); } private static List getProperties(Map toscaJson) { List values = null; Either, ResultStatusEnum> properties = ImportUtils.getProperties(toscaJson); if (properties.isLeft()) { values = new ArrayList<>(); Map propertiesMap = properties.left().value(); if (propertiesMap != null && !propertiesMap.isEmpty()) { for (Entry entry : propertiesMap.entrySet()) { String propName = entry.getKey(); PropertyDefinition propertyDefinition = entry.getValue(); PropertyDefinition newPropertyDefinition = new PropertyDefinition(propertyDefinition); newPropertyDefinition.setName(propName); values.add(newPropertyDefinition); } } } return values; } private static List append(List list, T value) { list.add(value); return list; } protected void setPropertiesMap(Map toscaJson, Consumer> consumer) { final List properties = getProperties(toscaJson); if (properties != null) { Map collect = properties.stream().collect(Collectors.toMap(PropertyDefinition::getName, Function.identity())); consumer.accept(collect); } } protected Either, ActionStatus> createElementTypesFromYml(String elementTypesYml, ICreateElementType, T> createApi) { List elementTypes; Map toscaJson = convertToFieldMap(elementTypesYml); if (toscaJson == null) { return Either.right(ActionStatus.INVALID_YAML_FILE); } elementTypes = createElementTypesFromToscaJsonMap(createApi, toscaJson); return Either.left(elementTypes); } @SuppressWarnings("unchecked") private Map convertToFieldMap(String elementTypesYml) { Map toscaJson = null; try { toscaJson = new Yaml().load(elementTypesYml); if (toscaJson.containsKey("data_types")){ toscaJson = (Map) toscaJson.get("data_types"); } } catch (Exception e) { log.debug("Failed to yaml file {}", elementTypesYml, e); } return toscaJson; } protected List createTypesFromToscaJsonMap(BiFunction, T> createApi, Map toscaJson) { List elementTypes = new ArrayList<>(); for (Entry elementTypeNameDataEntry : toscaJson.entrySet()) { String elementTypeName = elementTypeNameDataEntry.getKey(); Map elementTypeJsonData = (Map) elementTypeNameDataEntry.getValue(); T elementDefinition = createApi.apply(elementTypeName, elementTypeJsonData); elementTypes.add(elementDefinition); } return elementTypes; } protected List createElementTypesFromToscaJsonMap(ICreateElementType, T> createApi, Map toscaJson) { List elementTypes = new ArrayList<>(); for (Entry elementTypeNameDataEntry : toscaJson.entrySet()) { String elementTypeName = elementTypeNameDataEntry.getKey(); Map elementTypeJsonData = (Map) elementTypeNameDataEntry.getValue(); T elementDefinition = createApi.createElement(elementTypeName, elementTypeJsonData); elementTypes.add(elementDefinition); } return elementTypes; } protected Map createElementTypesMapFromToscaJsonMap(ICreateElementType, T> createApi, Map toscaJson) { Map elementTypesMap = new HashMap<>(); Iterator> elementTypesEntryItr = toscaJson.entrySet().iterator(); while (elementTypesEntryItr.hasNext()) { Entry elementTypeNameDataEntry = elementTypesEntryItr.next(); String elementTypeName = elementTypeNameDataEntry.getKey(); Map elementTypeJsonData = (Map) elementTypeNameDataEntry.getValue(); T elementDefinition = createApi.createElement(elementTypeName, elementTypeJsonData); elementTypesMap.put(elementTypeName, elementDefinition); } return elementTypesMap; } protected void setField(Map toscaJson, String fieldName, Consumer setter) { if (toscaJson.containsKey(fieldName)) { F fieldValue = (F) toscaJson.get(fieldName); setter.accept(fieldValue); } } private ActionStatus convertFromStorageResponseForElementType(StorageOperationStatus status, ElementTypeEnum elementTypeEnum) { ActionStatus ret; switch (elementTypeEnum) { case GROUP_TYPE: ret = componentsUtils.convertFromStorageResponseForGroupType(status); break; case POLICY_TYPE: ret = componentsUtils.convertFromStorageResponseForPolicyType(status); break; case DATA_TYPE: ret = componentsUtils.convertFromStorageResponseForDataType(status); break; case CAPABILITY_TYPE: ret = componentsUtils.convertFromStorageResponseForCapabilityType(status); break; case INTERFACE_LIFECYCLE_TYPE: ret = componentsUtils.convertFromStorageResponseForLifecycleType(status); break; case RELATIONSHIP_TYPE: ret = componentsUtils.convertFromStorageResponseForRelationshipType(status); break; default: ret = componentsUtils.convertFromStorageResponse(status); break; } return ret; } private ResponseFormat getResponseFormatForElementType(ActionStatus actionStatus, ElementTypeEnum elementTypeEnum, T elementTypeDefinition) { ResponseFormat ret; switch (elementTypeEnum) { case GROUP_TYPE: ret = componentsUtils.getResponseFormatByGroupType(actionStatus, (GroupTypeDefinition) elementTypeDefinition); break; case POLICY_TYPE: ret = componentsUtils.getResponseFormatByPolicyType(actionStatus, (PolicyTypeDefinition) elementTypeDefinition); break; case DATA_TYPE: ret = componentsUtils.getResponseFormatByDataType(actionStatus, (DataTypeDefinition) elementTypeDefinition, null); break; case CAPABILITY_TYPE: ret = componentsUtils.getResponseFormatByCapabilityType(actionStatus, (CapabilityTypeDefinition) elementTypeDefinition); break; default: ret = componentsUtils.getResponseFormat(actionStatus); break; } return ret; } private List> createTypesByDao(List elementTypesToCreate, TypeOperations typeOperations) { List> createdElementTypes = new ArrayList<>(); for (T newTypeDefinition : elementTypesToCreate) { try { String typeName = newTypeDefinition.getType(); T existingDefinition = typeOperations.getLatestType(typeName); if (existingDefinition == null /*new type*/) { typeOperations.addType(newTypeDefinition); } else { if (typeOperations.isSameType(newTypeDefinition, existingDefinition)) { propertyOperation.getJanusGraphGenericDao().rollback(); createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, null)); continue; } else { typeOperations.updateType(existingDefinition, newTypeDefinition); } } propertyOperation.getJanusGraphGenericDao().commit(); createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, true)); } catch (Exception e) { propertyOperation.getJanusGraphGenericDao().rollback(); createdElementTypes.add(new ImmutablePair<>(newTypeDefinition, false)); } } return createdElementTypes; } protected Either>, ResponseFormat> createElementTypesByDao(List elementTypesToCreate, Function> validator, Function> elementInfoGetter, Function> elementFetcher, Function> elementAdder, BiFunction> elementUpgrader) { List> createdElementTypes = new ArrayList<>(); Either>, ResponseFormat> eitherResult = Either.left(createdElementTypes); Iterator elementTypeItr = elementTypesToCreate.iterator(); try { while (elementTypeItr.hasNext()) { T elementType = elementTypeItr.next(); eitherResult = handleType(elementType, validator, elementInfoGetter, elementFetcher, elementAdder, elementUpgrader) .left() .map(elem -> append(createdElementTypes, elem)); if (eitherResult.isRight()) { break; } if (!elementTypeItr.hasNext()) { log.info("all {} were created successfully!!!", elementType); } } } catch (Exception e) { eitherResult = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); throw e; } finally { if (eitherResult.isLeft()) { propertyOperation.getJanusGraphGenericDao().commit(); } else { propertyOperation.getJanusGraphGenericDao().rollback(); } } return eitherResult; } private Either, ResponseFormat> handleType(T elementType, Function> validator, Function> elementInfoGetter, Function> elementFetcher, Function> elementAdder, BiFunction> elementUpgrader) { final ImmutablePair elementInfo = elementInfoGetter.apply(elementType); ElementTypeEnum elementTypeEnum = elementInfo.left; String elementName = elementInfo.right; Either validateElementType = validator.apply(elementType); if (validateElementType.isRight()) { ResponseFormat responseFormat = validateElementType.right().value(); log.debug("Failed in validation of element type: {}. Response is {}", elementType, responseFormat.getFormattedMessage()); return Either.right(responseFormat); } log.info("send {} : {} to dao for create", elementTypeEnum, elementName); Either findElementType = elementFetcher.apply(elementName); if (findElementType.isRight()) { StorageOperationStatus status = findElementType.right().value(); log.debug("searched {} finished with result:{}", elementTypeEnum, status); if (status != StorageOperationStatus.NOT_FOUND) { ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(status, elementTypeEnum), elementTypeEnum, elementType); return Either.right(responseFormat); } else { return addElementType(elementType, elementAdder, elementTypeEnum, elementName); } } else { if (elementUpgrader != null) { return updateElementType(elementType, elementUpgrader, elementTypeEnum, elementName, findElementType.left().value()); } else { // mshitrit Once GroupType Versions are supported add // code here log.debug("{} : {} already exists.", elementTypeEnum, elementName); return Either.left(new ImmutablePair<>(elementType, false)); } } } protected Either>, ResponseFormat> createElementTypesWithVersionByDao(List elementTypesToCreate, Function> validator, Function> elementInfoGetter, BiFunction> elementFetcher, Function> elementAdder, BiFunction> elementUpgrader, String modelName) { List> createdElementTypes = new ArrayList<>(); Either>, ResponseFormat> eitherResult = Either.left(createdElementTypes); Iterator elementTypeItr = elementTypesToCreate.iterator(); try { while (elementTypeItr.hasNext()) { T elementType = elementTypeItr.next(); eitherResult = handleTypeByDao(elementType, validator, elementInfoGetter, elementFetcher, elementAdder, elementUpgrader, modelName) .left() .map(elem -> append(createdElementTypes, elem)); if (eitherResult.isRight()) { break; } if (!elementTypeItr.hasNext()) { log.info("all {} were created successfully!!!", elementType); } } } catch (Exception e) { eitherResult = Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); throw e; } finally { if (eitherResult.isLeft()) { propertyOperation.getJanusGraphGenericDao().commit(); } else { propertyOperation.getJanusGraphGenericDao().rollback(); } } return eitherResult; } private Either, ResponseFormat> handleTypeByDao(T elementType, Function> validator, Function> elementInfoGetter, BiFunction> elementFetcher, Function> elementAdder, BiFunction> elementUpgrader, String modelName) { final ImmutablePair elementInfo = elementInfoGetter.apply(elementType); ElementTypeEnum elementTypeEnum = elementInfo.left; String elementName = elementInfo.right; Either validateElementType = validator.apply(elementType); if (validateElementType.isRight()) { ResponseFormat responseFormat = validateElementType.right().value(); log.debug("Failed in validation of element type: {}. Response is {}", elementType, responseFormat.getFormattedMessage()); return Either.right(responseFormat); } log.info("send {} : {} to dao for create", elementTypeEnum, elementName); Either findElementType = elementFetcher.apply(elementName, modelName); if (findElementType.isRight()) { StorageOperationStatus status = findElementType.right().value(); log.debug("searched {} finished with result:{}", elementTypeEnum, status); if (status != StorageOperationStatus.NOT_FOUND) { ResponseFormat responseFormat = getResponseFormatForElementType(convertFromStorageResponseForElementType(status, elementTypeEnum), elementTypeEnum, elementType); return Either.right(responseFormat); } else { return addElementType(elementType, elementAdder, elementTypeEnum, elementName); } } else { if (elementUpgrader != null) { return updateElementType(elementType, elementUpgrader, elementTypeEnum, elementName, findElementType.left().value()); } else { // mshitrit Once GroupType Versions are supported add // code here log.debug("{} : {} already exists.", elementTypeEnum, elementName); return Either.left(new ImmutablePair<>(elementType, false)); } } } private Either, ResponseFormat> addElementType(T elementType, Function> elementAdder, ElementTypeEnum elementTypeEnum, String elementName) { Either dataModelResponse = elementAdder.apply(elementType); if (dataModelResponse.isRight()) { BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("Create {}", elementTypeEnum.name()); log.debug("failed to create {}: {}", elementTypeEnum, elementName); if (dataModelResponse.right().value() != StorageOperationStatus.OK) { ResponseFormat responseFormat = getResponseFormatForElementType( convertFromStorageResponseForElementType(dataModelResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType); return Either.right(responseFormat); } else { return Either.left(new ImmutablePair<>(elementType, false)); } } else { log.debug("{} : {} was created successfully.", elementTypeEnum, elementName); return Either.left(new ImmutablePair<>(elementType, true)); } } private Either, ResponseFormat> updateElementType(T elementType, BiFunction> elementUpgrader, ElementTypeEnum elementTypeEnum, String elementName, T existingElementType) { Either upgradeResponse = elementUpgrader.apply(elementType, existingElementType); if (upgradeResponse.isRight()) { StorageOperationStatus status = upgradeResponse.right().value(); if (status == StorageOperationStatus.OK) { return Either.left(new ImmutablePair<>(elementType, false)); } else { ResponseFormat responseFormat = getResponseFormatForElementType( convertFromStorageResponseForElementType(upgradeResponse.right().value(), elementTypeEnum), elementTypeEnum, elementType); return Either.right(responseFormat); } } else { log.debug("{} : {} was upgraded successfully.", elementTypeEnum, elementName); return Either.left(new ImmutablePair<>(elementType, true)); } } public Either>, ResponseFormat> createElementTypes( ToscaTypeImportData toscaTypeImportData, BiFunction, ActionStatus>> elementTypeFromYmlCreater, BiFunction, String, Either>, ResponseFormat>> elementTypeDaoCreater, String modelName) { Either, ActionStatus> elementTypes = elementTypeFromYmlCreater.apply(toscaTypeImportData.getToscaTypesYml(), modelName); return elementTypes .right() .map(err -> componentsUtils.getResponseFormat(err, "")) .left() .map(toscaTypes -> enrichTypesWithNonToscaMetadata(toscaTypes, toscaTypeImportData.getToscaTypeMetadata())) .left() .bind(elementTypeList -> elementTypeDaoCreater.apply(elementTypeList, modelName)); } public List> createElementTypes(String toscaTypesYml, BiFunction, T> createApi, TypeOperations typeOperations) { Map fieldMap = convertToFieldMap(toscaTypesYml); if (fieldMap == null) { throw new ByActionStatusComponentException(ActionStatus.INVALID_YAML_FILE); } List elementTypes = createTypesFromToscaJsonMap(createApi, fieldMap); return createTypesByDao(elementTypes, typeOperations); } private List enrichTypesWithNonToscaMetadata(List toscaTypes, Map toscaTypeMetadata) { return toscaTypes.stream() .map(toscaType -> setNonToscaMetaDataOnType(toscaTypeMetadata, toscaType)) .collect(toList()); } private T setNonToscaMetaDataOnType(Map toscaTypeMetadata, T toscaTypeDefinition) { final String toscaType = toscaTypeDefinition.getType(); final ToscaTypeMetadata typeMetaData = toscaTypeMetadata.get(toscaType); if (typeMetaData == null) { log.debug("failing while trying to associate metadata for type {}. type not exist", toscaType); throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR); } toscaTypeDefinition.setIcon(typeMetaData.getIcon()); toscaTypeDefinition.setName(typeMetaData.getDisplayName()); return toscaTypeDefinition; } public Either>, ResponseFormat> createElementTypes(String elementTypesYml, Function, ActionStatus>> elementTypeFromYmlCreater, Function, Either>, ResponseFormat>> elementTypeDaoCreater, ElementTypeEnum elementTypeEnum) { Either, ActionStatus> elementTypes = elementTypeFromYmlCreater.apply(elementTypesYml); if (elementTypes.isRight()) { ActionStatus status = elementTypes.right().value(); ResponseFormat responseFormat = getResponseFormatForElementType(status, elementTypeEnum, null); return Either.right(responseFormat); } return elementTypeDaoCreater.apply(elementTypes.left().value()); } public void addTypesToDefaultImports(final ElementTypeEnum elementTypeEnum, final String typesYaml, final String modelName) { modelOperation.addTypesToDefaultImports(elementTypeEnum, typesYaml, modelName); } public void updateTypesInAdditionalTypesImport(final ElementTypeEnum elementTypeEnum, final String dataTypeYml, final String modelName) { modelOperation.updateTypesInAdditionalTypesImport(elementTypeEnum, dataTypeYml, modelName); } public interface ICreateElementType { T3 createElement(T1 firstArg, T2 secondArg); } }