diff options
Diffstat (limited to 'asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/DataTypesUpdate.java')
-rw-r--r-- | asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/DataTypesUpdate.java | 428 |
1 files changed, 428 insertions, 0 deletions
diff --git a/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/DataTypesUpdate.java b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/DataTypesUpdate.java new file mode 100644 index 0000000000..d7f36840c7 --- /dev/null +++ b/asdctool/src/main/java/org/openecomp/sdc/asdctool/impl/migration/v1702/DataTypesUpdate.java @@ -0,0 +1,428 @@ +/*- + * ============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========================================================= + */ + +package org.openecomp.sdc.asdctool.impl.migration.v1702; + +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.components.impl.ImportUtils; +import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum; +import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaTagNamesEnum; +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.DataTypeDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.resources.data.PropertyData; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.yaml.snakeyaml.Yaml; + +import fj.data.Either; + +/** + * Allows to update existing or create new data types according input file (yaml) + * @author ns019t + * + */ +public class DataTypesUpdate { + + private static Logger log = LoggerFactory.getLogger(Migration1702.class.getName()); + + @Autowired + private PropertyOperation propertyOperation; + @Autowired + private ComponentsUtils componentsUtils; + + @SuppressWarnings("unchecked") + /** + * Updates existing or creates new data types according input file (yaml) + * @param dataTypeYmlFilePath + * @return + */ + public boolean updateDataTypes(String dataTypeYmlFilePath) { + + + List<String> dataTypesToUpdate = new ArrayList<>(); + dataTypesToUpdate.add("org.openecomp.datatypes.EcompHoming"); + dataTypesToUpdate.add("org.openecomp.datatypes.EcompNaming"); + dataTypesToUpdate.add("org.openecomp.datatypes.network.NetworkAssignments"); + dataTypesToUpdate.add("org.openecomp.datatypes.network.ProviderNetwork"); + dataTypesToUpdate.add("org.openecomp.datatypes.network.NetworkFlows"); + dataTypesToUpdate.add("org.openecomp.datatypes.Artifact"); + dataTypesToUpdate.add("org.openecomp.datatypes.network.VlanRequirements"); + dataTypesToUpdate.add("org.openecomp.datatypes.network.IpRequirements"); + dataTypesToUpdate.add("org.openecomp.datatypes.network.MacAssignments"); + dataTypesToUpdate.add("org.openecomp.datatypes.network.MacRequirements"); + dataTypesToUpdate.add("org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPairIp"); + dataTypesToUpdate.add("org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress"); + dataTypesToUpdate.add("org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.Properties"); + dataTypesToUpdate.add("org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPair"); + dataTypesToUpdate.add("org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.AddressPairs"); + + boolean isSuccessful = true; + List<DataTypeDefinition> dataTypes = extractDataTypesFromYaml(dataTypeYmlFilePath); + + if(CollectionUtils.isEmpty(dataTypes)){ + isSuccessful = false; + } + + List<ImmutablePair<DataTypeDefinition, Boolean>> createdElementTypes = new ArrayList<>(); + + Iterator<DataTypeDefinition> elementTypeItr = dataTypes.iterator(); + if(isSuccessful ){ + try { + while (elementTypeItr.hasNext()) { + DataTypeDefinition elementType = elementTypeItr.next(); + String elementName = elementType.getName(); + Either<ActionStatus, ResponseFormat> validateElementType = validateDataType(elementType); + if (validateElementType.isRight()) { + log.debug("Failed to validate data type {}. Status is {}. ", elementName, validateElementType.right().value()); + isSuccessful = false; + break; + } + log.debug("Going to get data type by name {}. ", elementName); + Either<DataTypeDefinition, StorageOperationStatus> findElementType = propertyOperation.getDataTypeByNameWithoutDerived(elementName); + if (findElementType.isRight()) { + StorageOperationStatus status = findElementType.right().value(); + if (status != StorageOperationStatus.NOT_FOUND) { + log.debug("Failed to fetch data type {}. Status is {}. ", elementName , validateElementType.right().value()); + isSuccessful = false; + break; + } else { + log.debug("Going to add data type with name {}. ", elementName); + Either<DataTypeDefinition, StorageOperationStatus> dataModelResponse = propertyOperation.addDataType(elementType); + + if (dataModelResponse.isRight()) { + if (dataModelResponse.right().value() != StorageOperationStatus.SCHEMA_VIOLATION) { + log.debug("Failed to add data type {}. Status is {}. ", elementName , dataModelResponse.right().value()); + isSuccessful = false; + break; + } else { + createdElementTypes.add(new ImmutablePair<DataTypeDefinition, Boolean>(elementType, false)); + } + } else { + createdElementTypes.add(new ImmutablePair<DataTypeDefinition, Boolean>(elementType, true)); + } + + } + } else { + log.debug("Going to update data type with name {}. ", elementName); + Either<DataTypeDefinition, StorageOperationStatus> updateDataTypeRes = propertyOperation.updateDataType(elementType, findElementType.left().value()); + if (updateDataTypeRes.isRight()) { + StorageOperationStatus status = updateDataTypeRes.right().value(); + if (status == StorageOperationStatus.OK) { + createdElementTypes.add(new ImmutablePair<DataTypeDefinition, Boolean>(elementType, false)); + } else { + log.debug("Failed to update data type {}. Status is {}. ", elementName , updateDataTypeRes.right().value()); + isSuccessful = false; + break; + } + } else { + createdElementTypes.add(new ImmutablePair<DataTypeDefinition, Boolean>(elementType, true)); + } + } + } + } finally { + if(isSuccessful){ + propertyOperation.getTitanGenericDao().commit(); + }else{ + propertyOperation.getTitanGenericDao().rollback(); + } + } + } + return isSuccessful; + } + + @SuppressWarnings("unchecked") + static public List<DataTypeDefinition> extractDataTypesFromYaml(String dataTypeYmlFilePath) { + String dataTypeName; + List<DataTypeDefinition> dataTypes = new ArrayList<>(); + try { + File file = new File(dataTypeYmlFilePath); + FileReader fr = new FileReader(file); + Map<String, Object> toscaJson = (Map<String, Object>) new Yaml().load(fr); + + Iterator<Entry<String, Object>> elementTypesEntryItr = toscaJson.entrySet().iterator(); + while (elementTypesEntryItr.hasNext()) { + Entry<String, Object> elementTypeNameDataEntry = elementTypesEntryItr.next(); + dataTypeName = elementTypeNameDataEntry.getKey(); + Map<String, Object> elementTypeJsonData = (Map<String, Object>) elementTypeNameDataEntry.getValue(); + + DataTypeDefinition dataType = new DataTypeDefinition(); + dataType.setName(dataTypeName); + + if (elementTypeJsonData != null) { + + if (elementTypeJsonData.containsKey(ToscaTagNamesEnum.DESCRIPTION.getElementName())) { + dataType.setDescription( (String)elementTypeJsonData.get(ToscaTagNamesEnum.DESCRIPTION.getElementName())); + } + if (elementTypeJsonData.containsKey(ToscaTagNamesEnum.DERIVED_FROM.getElementName())) { + dataType.setDerivedFromName( (String)elementTypeJsonData.get(ToscaTagNamesEnum.DERIVED_FROM.getElementName())); + } + List<PropertyDefinition> properties = getProperties(elementTypeJsonData); + if (elementTypeJsonData.containsKey(ToscaTagNamesEnum.PROPERTIES.getElementName())) { + dataType.setProperties(properties); + } + } + dataTypes.add(dataType); + } + + } catch (Exception e) { + log.debug("Failed to extract data types from Yaml file {}. ", dataTypeYmlFilePath); + e.printStackTrace(); + } + return dataTypes; + } + + static public List<PropertyDefinition> getProperties(Map<String, Object> toscaJson) { + List<PropertyDefinition> values = null; + Either<Map<String, PropertyDefinition>, ResultStatusEnum> properties = ImportUtils.getProperties(toscaJson); + + if (properties.isLeft()) { + values = new ArrayList<>(); + Map<String, PropertyDefinition> propertiesMap = properties.left().value(); + if (propertiesMap != null && propertiesMap.isEmpty() == false) { + + for (Entry<String, PropertyDefinition> 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 Either<ActionStatus, ResponseFormat> validateDataType(DataTypeDefinition dataType) { + + String dataTypeName = dataType.getName(); + List<PropertyDefinition> properties = dataType.getProperties(); + if (properties == null) { + // At least one parameter should be defined either in the properties + // section or at one of the parents + String derivedDataType = dataType.getDerivedFromName(); + // If there are no properties, then we can create a data type if it + // is an abstract one or it derives from non abstract data type + if ((derivedDataType == null || derivedDataType.isEmpty())) { + if (false == isAbstract(dataType.getName())) { + if (false == ToscaPropertyType.isScalarType(dataTypeName)) { + log.debug("Data type {} must have properties unless it derives from non abstract data type",dataType.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM, dataType, null); + + return Either.right(responseFormat); + } + } + } else { + // if it is not a scalar data type and it derives from abstract + // data type, we should reject the request. + if (false == ToscaPropertyType.isScalarType(dataTypeName) && true == isAbstract(derivedDataType)) { + log.debug("Data type {} which derived from abstract data type must have at least one property",dataType.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_NOR_PROPERTIES_NEITHER_DERIVED_FROM, dataType, null); + + return Either.right(responseFormat); + } + } + } else { + // properties tag cannot be empty + if (properties.isEmpty()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROPERTIES_CANNOT_BE_EMPTY, dataType, null); + + return Either.right(responseFormat); + } + + // check no duplicates + Set<String> collect = properties.stream().map(p -> p.getName()).collect(Collectors.toSet()); + if (collect != null) { + if (properties.size() != collect.size()) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_DUPLICATE_PROPERTY, dataType, null); + + return Either.right(responseFormat); + } + } + + List<String> propertiesWithSameTypeAsDataType = properties.stream().filter(p -> p.getType().equals(dataType.getName())).map(p -> p.getName()).collect(Collectors.toList()); + if (propertiesWithSameTypeAsDataType != null && propertiesWithSameTypeAsDataType.isEmpty() == false) { + log.debug("The data type {} contains properties with the type {}",dataType.getName(),dataType.getName()); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROEPRTY_CANNOT_HAVE_SAME_TYPE_OF_DATA_TYPE, dataType, propertiesWithSameTypeAsDataType); + + return Either.right(responseFormat); + } + } + + String derivedDataType = dataType.getDerivedFromName(); + if (derivedDataType != null) { + Either<DataTypeDefinition, StorageOperationStatus> derivedDataTypeByName = propertyOperation.getDataTypeByName(derivedDataType, true); + if (derivedDataTypeByName.isRight()) { + StorageOperationStatus status = derivedDataTypeByName.right().value(); + if (status == StorageOperationStatus.NOT_FOUND) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_DERIVED_IS_MISSING, dataType, null); + + return Either.right(responseFormat); + } else { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.GENERAL_ERROR, dataType, null); + + return Either.right(responseFormat); + + } + } else { + + DataTypeDefinition derivedDataTypeDef = derivedDataTypeByName.left().value(); + if (properties != null && properties.isEmpty() == false) { + + if (true == isScalarType(derivedDataTypeDef)) { + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_CANNOT_HAVE_PROPERTIES, dataType, null); + + return Either.right(responseFormat); + } + + Set<String> allParentsProps = new HashSet<>(); + do { + List<PropertyDefinition> currentParentsProps = derivedDataTypeDef.getProperties(); + if (currentParentsProps != null) { + for (PropertyDefinition propertyDefinition : currentParentsProps) { + allParentsProps.add(propertyDefinition.getName()); + } + } + derivedDataTypeDef = derivedDataTypeDef.getDerivedFrom(); + } while (derivedDataTypeDef != null); + + // Check that no property is already defined in one of the + // ancestors + Set<String> alreadyExistPropsCollection = properties.stream().filter(p -> allParentsProps.contains(p.getName())).map(p -> p.getName()).collect(Collectors.toSet()); + if (alreadyExistPropsCollection != null && alreadyExistPropsCollection.isEmpty() == false) { + List<String> duplicateProps = new ArrayList<>(); + duplicateProps.addAll(alreadyExistPropsCollection); + ResponseFormat responseFormat = componentsUtils.getResponseFormatByDataType(ActionStatus.DATA_TYPE_PROPERTY_ALREADY_DEFINED_IN_ANCESTOR, dataType, duplicateProps); + + return Either.right(responseFormat); + } + + } + } + } + return Either.left(ActionStatus.OK); + } + + private boolean isAbstract(String dataTypeName) { + + ToscaPropertyType isPrimitiveToscaType = ToscaPropertyType.isValidType(dataTypeName); + + return isPrimitiveToscaType != null && isPrimitiveToscaType.isAbstract() == true; + + } + + private boolean isScalarType(DataTypeDefinition dataTypeDef) { + + boolean isScalar = false; + DataTypeDefinition dataType = dataTypeDef; + + while (dataType != null) { + + String name = dataType.getName(); + if (ToscaPropertyType.isScalarType(name)) { + isScalar = true; + break; + } + + dataType = dataType.getDerivedFrom(); + } + + return isScalar; + } + +// public Either<DataTypeDefinition, StorageOperationStatus> updateDataType(DataTypeDefinition newDataTypeDefinition, DataTypeDefinition oldDataTypeDefinition) { +// +// Either<DataTypeDefinition, StorageOperationStatus> result = null; +// +// try { +// +// List<PropertyDefinition> newProperties = newDataTypeDefinition.getProperties(); +// +// List<PropertyDefinition> oldProperties = oldDataTypeDefinition.getProperties(); +// +// String newDerivedFromName = getDerivedFromName(newDataTypeDefinition); +// +// String oldDerivedFromName = getDerivedFromName(oldDataTypeDefinition); +// +// String dataTypeName = newDataTypeDefinition.getName(); +// +// List<PropertyDefinition> propertiesToAdd = new ArrayList<>(); +// if (isPropertyOmitted(newProperties, oldProperties, dataTypeName) || isPropertyTypeChanged(dataTypeName, newProperties, oldProperties, propertiesToAdd) || isDerivedFromNameChanged(dataTypeName, newDerivedFromName, oldDerivedFromName)) { +// +// log.debug("The new data type " + dataTypeName + " is invalid."); +// +// result = Either.right(StorageOperationStatus.CANNOT_UPDATE_EXISTING_ENTITY); +// return result; +// } +// +// if (propertiesToAdd == null || propertiesToAdd.isEmpty()) { +// log.debug("No new properties has been defined in the new data type " + newDataTypeDefinition); +// result = Either.right(StorageOperationStatus.OK); +// return result; +// } +// +// Either<Map<String, PropertyData>, TitanOperationStatus> addPropertiesToDataType = addPropertiesToDataType(oldDataTypeDefinition.getUniqueId(), propertiesToAdd); +// +// if (addPropertiesToDataType.isRight()) { +// log.debug("Failed to update data type {} to Graph. Status is {}", oldDataTypeDefinition, addPropertiesToDataType.right().value().name()); +// BeEcompErrorManager.getInstance().logBeFailedAddingNodeTypeError("UpdateDataType", "Property"); +// result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(addPropertiesToDataType.right().value())); +// return result; +// } else { +// +// Either<DataTypeDefinition, TitanOperationStatus> dataTypeByUid = this.getDataTypeByUid(oldDataTypeDefinition.getUniqueId()); +// if (dataTypeByUid.isRight()) { +// TitanOperationStatus status = addPropertiesToDataType.right().value(); +// log.debug("Failed to get data type {} after update. Status is {}", oldDataTypeDefinition.getUniqueId(), status.name()); +// BeEcompErrorManager.getInstance().logBeFailedRetrieveNodeError("UpdateDataType", "Property", status.name()); +// result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(status)); +// } else { +// result = Either.left(dataTypeByUid.left().value()); +// } +// } +// +// return result; +// +// } +// } + +} |