diff options
5 files changed, 153 insertions, 19 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DataTypeServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DataTypeServlet.java index a7327bf184..13e2ba3259 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DataTypeServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/DataTypeServlet.java @@ -144,21 +144,22 @@ public class DataTypeServlet extends BeGenericServlet { public Response createProperty(@Parameter(in = ParameterIn.PATH, required = true, description = "The data type id") @PathParam("id") final String id, @RequestBody(description = "Property to add", required = true) final PropertyDefinitionDto propertyDefinitionDto) { - Optional<DataTypeDataDefinition> dataType = dataTypeOperation.getDataTypeByUid(id); - dataType.ifPresentOrElse(dt -> { - String model = dt.getModel(); - Optional<DataTypeDataDefinition> propertyDataType = dataTypeOperation.getDataTypeByNameAndModel(propertyDefinitionDto.getType(), model); - if (propertyDataType.isEmpty()) { - if (model == null || model.isEmpty()) { - model = "SDC AID"; - } - throw new OperationException(ActionStatus.INVALID_MODEL, - String.format("Property model is not the same as the data type model. Must be be '%s'", model)); - } - }, () -> { + Optional<DataTypeDataDefinition> dataTypeOptional = dataTypeOperation.getDataTypeByUid(id); + dataTypeOptional.orElseThrow(() -> { throw new OperationException(ActionStatus.DATA_TYPE_NOT_FOUND, String.format("Failed to find data type '%s'", id)); }); + DataTypeDataDefinition dataType = dataTypeOptional.get(); + String model = dataType.getModel(); + Optional<DataTypeDataDefinition> propertyDataType = dataTypeOperation.getDataTypeByNameAndModel(propertyDefinitionDto.getType(), model); + if (propertyDataType.isEmpty()) { + if (model == null || model.isEmpty()) { + model = "SDC AID"; + } + throw new OperationException(ActionStatus.INVALID_MODEL, + String.format("Property model is not the same as the data type model. Must be be '%s'", model)); + } final PropertyDefinitionDto property = dataTypeOperation.createProperty(id, propertyDefinitionDto); + dataTypeOperation.addPropertyToAdditionalTypeDataType(dataType, property); dataTypeBusinessLogic.updateApplicationDataTypeCache(id); return Response.status(Status.CREATED).entity(property).build(); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java index 7d01f3f273..103221cb76 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java @@ -50,6 +50,7 @@ import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException; import org.openecomp.sdc.be.model.mapper.PropertyDefinitionDtoMapper; +import org.openecomp.sdc.be.model.normatives.ElementTypeEnum; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.resources.data.DataTypeData; import org.openecomp.sdc.be.resources.data.PropertyData; @@ -279,4 +280,8 @@ public class DataTypeOperation extends AbstractOperation { return PropertyDefinitionDtoMapper.mapFrom(propertyDataDefinition); } + public void addPropertyToAdditionalTypeDataType(DataTypeDataDefinition dataTypeDataDefinition, PropertyDefinitionDto property) { + modelOperation.addPropertyToAdditionalType(ElementTypeEnum.DATA_TYPE, property, dataTypeDataDefinition.getModel(), dataTypeDataDefinition.getName()); + } + } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java index 8baa9a73c0..2e35c30e06 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java @@ -54,14 +54,15 @@ import org.openecomp.sdc.be.data.model.ToscaImportByModel; import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; -import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.Model; +import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException; import org.openecomp.sdc.be.model.normatives.ElementTypeEnum; import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.resources.data.ModelData; +import org.openecomp.sdc.be.utils.TypeUtils; import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode; import org.openecomp.sdc.common.log.wrappers.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -424,10 +425,69 @@ public class ModelOperation { final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName); return modelImportList.stream().filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny(); } - + private Map<String, Object> getExistingTypes(final ElementTypeEnum elementTypeEnum, final ToscaImportByModel additionalTypeDefinitionsImport) { final Map<String, Object> existingContent = new Yaml().load(additionalTypeDefinitionsImport.getContent()); return (Map<String, Object>) existingContent.get(elementTypeEnum.getToscaEntryName()); } + public void addPropertyToAdditionalType(final ElementTypeEnum elementTypeEnum, final PropertyDefinitionDto property, + final String modelName, final String name) { + final List<ToscaImportByModel> modelImportList = toscaModelImportCassandraDao.findAllByModel(modelName); + final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = modelImportList.stream() + .filter(t -> ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(t.getFullPath()))).findAny(); + final ToscaImportByModel additionalTypeDefinitionsImport; + final List<ToscaImportByModel> rebuiltModelImportList; + if (additionalTypeDefinitionsImportOptional.isEmpty()) { + return; + } + additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get(); + rebuiltModelImportList = modelImportList.stream() + .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath()))) + .collect(Collectors.toList()); + final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent()); + additionalTypeDefinitionsImport.setContent(buildPropertyAdditionalTypeDefinitionContent(elementTypeEnum, name, property, originalContent)); + rebuiltModelImportList.add(additionalTypeDefinitionsImport); + toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList); + } + + private String buildPropertyAdditionalTypeDefinitionContent(final ElementTypeEnum elementTypeEnum, final String name, + final PropertyDefinitionDto property, final Map<String, Object> originalContent) { + final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName()); + Map<String, Object> typeContent = (Map<String, Object>) originalTypeContent.get(name); + Map<String, Object> typeProperties = (Map<String, Object>) typeContent.get("properties"); + if (typeProperties == null) { + typeProperties = new HashMap<>(); + } + Map<String, Object> typeProp = constructProperty(property); + typeProperties.put(property.getName(), typeProp); + typeContent.put("properties", typeProperties); + return new YamlUtil().objectToYaml(originalContent); + } + + private Map<String, Object> constructProperty(final PropertyDefinitionDto property) { + Map<String, Object> typeProp = new HashMap<>(); + if (property.getType() != null) { + typeProp.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getType()); + } + if (property.getDescription() != null) { + typeProp.put(TypeUtils.ToscaTagNamesEnum.DESCRIPTION.getElementName(), property.getDescription()); + } + Map<String, Object> schema = new HashMap<>(); + if (property.getSchemaType() != null) { + schema.put(TypeUtils.ToscaTagNamesEnum.TYPE.getElementName(), property.getSchemaType()); + typeProp.put(TypeUtils.ToscaTagNamesEnum.ENTRY_SCHEMA.getElementName(), schema); + } + if (property.getDefaultValue() != null) { + typeProp.put(TypeUtils.ToscaTagNamesEnum.DEFAULT.getElementName(), property.getDefaultValue()); + } + if (property.getRequired() != null) { + typeProp.put(TypeUtils.ToscaTagNamesEnum.REQUIRED.getElementName(), property.getRequired()); + } + if (property.getConstraints() != null) { + typeProp.put(TypeUtils.ToscaTagNamesEnum.CONSTRAINTS.getElementName(), property.getConstraints()); + } + return typeProp; + } + } diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java index acff2a3aa2..8fe89216fa 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelOperationTest.java @@ -16,6 +16,7 @@ * SPDX-License-Identifier: Apache-2.0 * ============LICENSE_END========================================================= */ + package org.openecomp.sdc.be.model.operations.impl; import static org.assertj.core.api.Assertions.assertThat; @@ -43,6 +44,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -72,6 +74,7 @@ import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.Model; import org.openecomp.sdc.be.model.ModelTestBase; +import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ModelOperationExceptionSupplier; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException; import org.openecomp.sdc.be.model.normatives.ElementTypeEnum; @@ -504,26 +507,27 @@ class ModelOperationTest extends ModelTestBase { final ToscaImportByModel actualImport1 = actualImportList.stream().filter(expectedImport1::equals).findFirst().orElse(null); assertNotNull(actualImport1); assertEquals(expectedImport1.getContent(), actualImport1.getContent()); - + // Update the added additional type final var updatedDataTypesPath = testResourcePath.resolve(Path.of("input-data_types-updated.yaml")); final var updatedDataTypes = Files.readString(updatedDataTypesPath); modelOperation.updateTypesInAdditionalTypesImport(ElementTypeEnum.DATA_TYPE, updatedDataTypes, modelName); - + ArgumentCaptor<List<ToscaImportByModel>> updatedImportListArgumentCaptor = ArgumentCaptor.forClass(List.class); verify(toscaModelImportCassandraDao, times(2)).saveAll(eq(modelName), updatedImportListArgumentCaptor.capture()); final List<ToscaImportByModel> updatedActualImportList = updatedImportListArgumentCaptor.getValue(); assertEquals(2, updatedActualImportList.size()); - + var expectedUpdatedAdditionalTypesImport = new ToscaImportByModel(); expectedUpdatedAdditionalTypesImport.setModelId(modelName); expectedUpdatedAdditionalTypesImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString()); - expectedUpdatedAdditionalTypesImport.setContent(Files.readString(testResourcePath.resolve(Path.of("expected-additional_types-2-updated.yaml")))); + expectedUpdatedAdditionalTypesImport.setContent( + Files.readString(testResourcePath.resolve(Path.of("expected-additional_types-2-updated.yaml")))); final ToscaImportByModel actualUpdatedAdditionalTypesImport = actualImportList.stream().filter(expectedUpdatedAdditionalTypesImport::equals).findFirst().orElse(null); assertNotNull(actualUpdatedAdditionalTypesImport); - + assertTrue(actualUpdatedAdditionalTypesImport.getContent().contains("added_property_1")); assertTrue(actualUpdatedAdditionalTypesImport.getContent().contains("added_property_2")); } @@ -582,6 +586,50 @@ class ModelOperationTest extends ModelTestBase { } + @Test + void addPropertyToExistingAdditionalType() throws IOException { + var modelName = "model"; + final Path testResourcePath = Path.of("src/test/resources/modelOperation"); + + var originalAdditionalTypesImport = new ToscaImportByModel(); + originalAdditionalTypesImport.setModelId(modelName); + originalAdditionalTypesImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString()); + final Path originalAdditionalTypesImportPath = testResourcePath.resolve(Path.of("original-additional_types-1.yaml")); + originalAdditionalTypesImport.setContent(Files.readString(originalAdditionalTypesImportPath)); + + final List<ToscaImportByModel> modelImports = new ArrayList<>(); + modelImports.add(originalAdditionalTypesImport); + when(toscaModelImportCassandraDao.findAllByModel(modelName)).thenReturn(modelImports); + + PropertyDefinitionDto property = new PropertyDefinitionDto(); + property.setName("addedMapProperty"); + property.setType("map"); + property.setSchemaType("string"); + property.setDescription("This is a description"); + Map<Object, Object> defaultValue = new HashMap<>(); + defaultValue.put("k1", "v1"); + defaultValue.put("k2", "v2"); + property.setDefaultValue(defaultValue); + property.setRequired(true); + + String dataTypeName = "tosca.datatypes.nfv.PreviouslyExistingType1"; + modelOperation.addPropertyToAdditionalType(ElementTypeEnum.DATA_TYPE, property, modelName, dataTypeName); + ArgumentCaptor<List<ToscaImportByModel>> importListArgumentCaptor = ArgumentCaptor.forClass(List.class); + verify(toscaModelImportCassandraDao).saveAll(eq(modelName), importListArgumentCaptor.capture()); + + final List<ToscaImportByModel> actualImportList = importListArgumentCaptor.getValue(); + assertEquals(1, actualImportList.size()); + + var expectedAdditionalTypesImport = new ToscaImportByModel(); + expectedAdditionalTypesImport.setModelId(modelName); + expectedAdditionalTypesImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString()); + expectedAdditionalTypesImport.setContent(Files.readString(testResourcePath.resolve(Path.of("expected-additional_types-4.yaml")))); + final ToscaImportByModel actualAdditionalTypesImport = + actualImportList.stream().filter(expectedAdditionalTypesImport::equals).findFirst().orElse(null); + assertNotNull(actualAdditionalTypesImport); + assertEquals(expectedAdditionalTypesImport.getContent(), actualAdditionalTypesImport.getContent()); + } + private ToscaImportByModel createModelImport(final String parentModelName, final String importPath) { var toscaImportByModel = new ToscaImportByModel(); toscaImportByModel.setModelId(parentModelName); diff --git a/catalog-model/src/test/resources/modelOperation/expected-additional_types-4.yaml b/catalog-model/src/test/resources/modelOperation/expected-additional_types-4.yaml new file mode 100644 index 0000000000..2d8fb24ab3 --- /dev/null +++ b/catalog-model/src/test/resources/modelOperation/expected-additional_types-4.yaml @@ -0,0 +1,20 @@ +tosca_definitions_version: tosca_simple_yaml_1_3 +description: Auto-generated file that contains package custom types or types added + after system installation. +data_types: + tosca.datatypes.nfv.PreviouslyExistingType1: + derived_from: tosca.datatypes.Root + description: additional type + properties: + addedMapProperty: + default: + k1: v1 + k2: v2 + entry_schema: + type: string + description: This is a description + type: map + required: true + tosca.datatypes.nfv.PreviouslyExistingType2: + derived_from: tosca.datatypes.Root + description: additional type |