*/
package org.openecomp.sdc.be.model.operations.impl;
+import static org.openecomp.sdc.common.api.Constants.ADDITIONAL_TYPE_DEFINITIONS;
+
import fj.data.Either;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
+import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.openecomp.sdc.be.dao.cassandra.ToscaModelImportCassandraDao;
import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
+import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao;
import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
-import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao;
import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
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.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;
public class ModelOperation {
private static final Logger log = Logger.getLogger(ModelOperation.class);
- private static final String ADDITIONAL_TYPE_DEFINITIONS = "additional_type_definitions.yml";
+ static final Path ADDITIONAL_TYPE_DEFINITIONS_PATH = Path.of(ADDITIONAL_TYPE_DEFINITIONS);
private final JanusGraphGenericDao janusGraphGenericDao;
private final JanusGraphDao janusGraphDao;
private final ToscaModelImportCassandraDao toscaModelImportCassandraDao;
private final DerivedFromOperation derivedFromOperation;
+ private ModelElementOperation modelElementOperation;
@Autowired
public ModelOperation(final JanusGraphGenericDao janusGraphGenericDao,
public Model createModel(final Model model, final boolean inTransaction) {
Model result = null;
- final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()));
+ final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType());
try {
final Either<ModelData, JanusGraphOperationStatus> createNode = janusGraphGenericDao.createNode(modelData, ModelData.class);
if (createNode.isRight()) {
String.format("Failed to create model %s on JanusGraph with %s error", model, janusGraphOperationStatus));
}
addDerivedFromRelation(model);
- result = new Model(createNode.left().value().getName(), model.getDerivedFrom());
+ result = new Model(createNode.left().value().getName(), model.getDerivedFrom(), model.getModelType());
return result;
} finally {
if (!inTransaction) {
toscaImportByModel.setContent(content);
return toscaImportByModel;
}).collect(Collectors.toList());
- toscaModelImportCassandraDao.importAll(modelId, toscaImportByModelList);
+ toscaModelImportCassandraDao.replaceImports(modelId, toscaImportByModelList);
+ }
+
+ /**
+ * Find all the model default imports, with the option to include the default imports from the parent model.
+ *
+ * @param modelId the model id
+ * @param includeParent a flag to include the parent model imports.
+ * @return the list of model default imports, or an empty list if no imports were found.
+ */
+ public List<ToscaImportByModel> findAllModelImports(final String modelId, final boolean includeParent) {
+ final List<ToscaImportByModel> toscaImportByModelList = toscaModelImportCassandraDao.findAllByModel(modelId);
+ if (includeParent) {
+ findModelByName(modelId).ifPresent(model -> {
+ if (model.getDerivedFrom() != null) {
+ toscaImportByModelList.addAll(toscaModelImportCassandraDao.findAllByModel(model.getDerivedFrom()));
+ }
+ });
+ }
+ toscaImportByModelList.sort((o1, o2) -> {
+ final int modelIdComparison = o1.getModelId().compareTo(o2.getModelId());
+ if (modelIdComparison == 0) {
+ return o1.getFullPath().compareTo(o2.getFullPath());
+ }
+ return modelIdComparison;
+ });
+ return toscaImportByModelList;
}
/**
public List<Model> findAllModels() {
return findModelsByCriteria(Collections.emptyMap());
}
+
+ public List<Model> findModels(final ModelTypeEnum modelType) {
+ final Map<GraphPropertyEnum, Object> propertyCriteria = new EnumMap<>(GraphPropertyEnum.class);
+ propertyCriteria.put(GraphPropertyEnum.MODEL_TYPE, modelType.getValue());
+
+ return findModelsByCriteria(propertyCriteria);
+ }
private List<Model> findModelsByCriteria(final Map<GraphPropertyEnum, Object> propertyCriteria) {
final List<GraphVertex> modelVerticesByCriteria = findModelVerticesByCriteria(propertyCriteria);
private Model convertToModel(final GraphVertex modelGraphVertex) {
final String modelName = (String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME);
-
+ final String modelTypeProperty = (String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.MODEL_TYPE);
+ ModelTypeEnum modelType = ModelTypeEnum.NORMATIVE;
+ final Optional<ModelTypeEnum> optionalModelTypeEnum = ModelTypeEnum.findByValue(modelTypeProperty);
+ if (optionalModelTypeEnum.isPresent()) {
+ modelType = optionalModelTypeEnum.get();
+ }
+
final Either<ImmutablePair<ModelData, GraphEdge>, JanusGraphOperationStatus> parentNode =
janusGraphGenericDao.getChild(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.Model), UniqueIdBuilder.buildModelUid(modelName),
GraphEdgeLabels.DERIVED_FROM, NodeTypeEnum.Model, ModelData.class);
log.error(EcompLoggerErrorCode.DATA_ERROR, this.getClass().getName(), operationException.getMessage());
throw operationException;
}
- return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME));
+ return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME), modelType);
} else {
final ModelData parentModel = parentNode.left().value().getKey();
- return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME), parentModel.getName());
+ return new Model((String) modelGraphVertex.getMetadataProperty(GraphPropertyEnum.NAME), parentModel.getName(), modelType);
}
}
- public void addTypesToDefaultImports(final String typesYaml, final String modelName) {
- final List<ToscaImportByModel> allSchemaImportsByModel = toscaModelImportCassandraDao.findAllByModel(modelName);
- final Optional<ToscaImportByModel> additionalTypeDefinitionsOptional = allSchemaImportsByModel.stream()
- .filter(t -> ADDITIONAL_TYPE_DEFINITIONS.equals(t.getFullPath())).findAny();
- final ToscaImportByModel toscaImportByModelAdditionalTypeDefinitions;
- final List<ToscaImportByModel> schemaImportsByModel;
- if (additionalTypeDefinitionsOptional.isPresent()) {
- toscaImportByModelAdditionalTypeDefinitions = additionalTypeDefinitionsOptional.get();
- schemaImportsByModel = allSchemaImportsByModel.stream()
- .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS.equals(toscaImportByModel.getFullPath()))
+ public void addTypesToDefaultImports(final ElementTypeEnum elementTypeEnum, final String typesYaml, final String modelName) {
+ 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.isPresent()) {
+ additionalTypeDefinitionsImport = additionalTypeDefinitionsImportOptional.get();
+ rebuiltModelImportList = modelImportList.stream()
+ .filter(toscaImportByModel -> !ADDITIONAL_TYPE_DEFINITIONS_PATH.equals(Path.of(toscaImportByModel.getFullPath())))
.collect(Collectors.toList());
} else {
- toscaImportByModelAdditionalTypeDefinitions = new ToscaImportByModel();
- toscaImportByModelAdditionalTypeDefinitions.setModelId(modelName);
- toscaImportByModelAdditionalTypeDefinitions.setFullPath(ADDITIONAL_TYPE_DEFINITIONS);
- toscaImportByModelAdditionalTypeDefinitions.setContent(typesYaml);
- schemaImportsByModel = new ArrayList<>(allSchemaImportsByModel);
+ additionalTypeDefinitionsImport = new ToscaImportByModel();
+ additionalTypeDefinitionsImport.setModelId(modelName);
+ additionalTypeDefinitionsImport.setFullPath(ADDITIONAL_TYPE_DEFINITIONS_PATH.toString());
+ additionalTypeDefinitionsImport.setContent(createAdditionalTypeDefinitionsHeader());
+ rebuiltModelImportList = new ArrayList<>(modelImportList);
}
- final List<ToscaImportByModel> toscaImportByModels = removeExistingDefaultImports(typesYaml, schemaImportsByModel);
+ final Map<String, Object> typesYamlMap = new Yaml().load(typesYaml);
+ removeExistingTypesFromDefaultImports(elementTypeEnum, typesYamlMap, rebuiltModelImportList);
- final Map<String, Object> originalContent = (Map<String, Object>) new Yaml().load(toscaImportByModelAdditionalTypeDefinitions.getContent());
- toscaImportByModelAdditionalTypeDefinitions.setContent(buildAdditionalTypeDefinitionsContent(typesYaml, originalContent).toString());
- toscaImportByModels.add(toscaImportByModelAdditionalTypeDefinitions);
+ final Map<String, Object> originalContent = new Yaml().load(additionalTypeDefinitionsImport.getContent());
+ additionalTypeDefinitionsImport.setContent(buildAdditionalTypeDefinitionsContent(elementTypeEnum, typesYamlMap, originalContent));
+ rebuiltModelImportList.add(additionalTypeDefinitionsImport);
- toscaModelImportCassandraDao.importOnly(modelName, toscaImportByModels);
+ toscaModelImportCassandraDao.saveAll(modelName, rebuiltModelImportList);
}
- private List<ToscaImportByModel> removeExistingDefaultImports(final String typesYaml, final List<ToscaImportByModel> schemaImportsByModel) {
- final List<ToscaImportByModel> toscaImportByModels = new ArrayList<>();
- schemaImportsByModel.forEach(toscaImportByModel -> {
- final ToscaImportByModel toscaImportByModelNew = new ToscaImportByModel();
- toscaImportByModelNew.setModelId(toscaImportByModel.getModelId());
- toscaImportByModelNew.setFullPath(toscaImportByModel.getFullPath());
+ private void removeExistingTypesFromDefaultImports(final ElementTypeEnum elementTypeEnum, final Map<String, Object> typesYaml,
+ final List<ToscaImportByModel> defaultImportList) {
+ defaultImportList.forEach(toscaImportByModel -> {
+ final Map<String, Object> existingImportYamlMap = new Yaml().load(toscaImportByModel.getContent());
+ final Map<String, Object> currentTypeYamlMap = (Map<String, Object>) existingImportYamlMap.get(elementTypeEnum.getToscaEntryName());
+ if (MapUtils.isNotEmpty(currentTypeYamlMap)) {
+ typesYaml.keySet().forEach(currentTypeYamlMap::remove);
+ }
+ toscaImportByModel.setContent(new YamlUtil().objectToYaml(existingImportYamlMap));
+ });
+ }
- final Map<String, Object> existingImportYamlMap = (Map<String, Object>) new Yaml().load(toscaImportByModel.getContent());
+ private String buildAdditionalTypeDefinitionsContent(final ElementTypeEnum elementTypeEnum, final Map<String, Object> typesYamlMap,
+ final Map<String, Object> originalContent) {
+ final Map<String, Object> originalTypeContent = (Map<String, Object>) originalContent.get(elementTypeEnum.getToscaEntryName());
+ if (MapUtils.isEmpty(originalTypeContent)) {
+ originalContent.put(elementTypeEnum.getToscaEntryName(), new LinkedHashMap<>(typesYamlMap));
+ } else {
+ originalTypeContent.putAll(typesYamlMap);
+ }
+ return new YamlUtil().objectToYaml(originalContent);
+ }
- ((Map<String, Object>) new Yaml().load(typesYaml)).keySet().forEach(existingImportYamlMap::remove);
+ private String createAdditionalTypeDefinitionsHeader() {
+ return "tosca_definitions_version: tosca_simple_yaml_1_3" + "\n"
+ + "description: Auto-generated file that contains package custom types or types added after system installation." + "\n";
+ }
- final StringBuilder stringBuilder = new StringBuilder();
- existingImportYamlMap.forEach((key, value) -> {
- final Map<Object, Object> hashMap = new HashMap<>();
- hashMap.put(key, value);
- stringBuilder.append("\n").append(new YamlUtil().objectToYaml(hashMap));
- });
+ /**
+ * Deletes the given model if it exists, along with its MODEL_ELEMENT edges and import files.
+ *
+ * @param model the model
+ * @param inTransaction if the operation is called in the middle of a janusgraph transaction
+ */
+ public void deleteModel(final Model model, final boolean inTransaction) {
+ boolean rollback = false;
- toscaImportByModelNew.setContent(stringBuilder.toString());
- toscaImportByModels.add(toscaImportByModelNew);
- });
- return toscaImportByModels;
+ try {
+ final GraphVertex modelVertexByName = findModelVertexByName(model.getName()).orElse(null);
+ if (modelVertexByName == null) {
+ return;
+ }
+ toscaModelImportCassandraDao.deleteAllByModel(model.getName());
+ modelElementOperation.deleteModelElements(model, inTransaction);
+ deleteModel(model);
+ } catch (final OperationException e) {
+ rollback = true;
+ throw e;
+ } catch (final Exception e) {
+ rollback = true;
+ throw new OperationException(e, ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
+ } finally {
+ if (!inTransaction) {
+ if (rollback) {
+ janusGraphGenericDao.rollback();
+ } else {
+ janusGraphGenericDao.commit();
+ }
+ }
+ }
+ }
+
+ private void deleteModel(final Model model) {
+ final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType());
+ final Either<ModelData, JanusGraphOperationStatus> deleteParentNodeByModel = janusGraphGenericDao.deleteNode(modelData, ModelData.class);
+ if (deleteParentNodeByModel.isRight()) {
+ final var janusGraphOperationStatus = deleteParentNodeByModel.right().value();
+ log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(),
+ "Failed to delete model {} on JanusGraph with status {}", new Object[] {model.getName(), janusGraphOperationStatus});
+ throw new OperationException(ActionStatus.COULD_NOT_DELETE_MODEL, model.getName());
+ }
+ }
+
+ @Autowired
+ public void setModelElementOperation(final ModelElementOperation modelElementOperation) {
+ this.modelElementOperation = modelElementOperation;
}
- private StringBuilder buildAdditionalTypeDefinitionsContent(final String typesYaml, final Map<String, Object> originalContent) {
- final var stringBuilder = new StringBuilder();
+ @SuppressWarnings("unchecked")
+ public void updateTypesInAdditionalTypesImport(final ElementTypeEnum elementTypeEnum, final String typesYaml, final String modelName) {
+ final Optional<ToscaImportByModel> additionalTypeDefinitionsImportOptional = getAdditionalTypes(modelName);
+
+ if (additionalTypeDefinitionsImportOptional.isPresent()) {
+
+ final Map<String, Object> existingTypeContent = getExistingTypes(elementTypeEnum, additionalTypeDefinitionsImportOptional.get());
+ final Set<String> existingTypeNames = existingTypeContent.keySet();
+
+ final Map<String, Object> typesToUpate = new HashMap<>();
+
+ final Map<String, Object> newTypesYaml = new Yaml().load(typesYaml);
+ newTypesYaml.entrySet().stream().filter(entry -> existingTypeNames.contains(entry.getKey())).forEach(newTypeToUpdate -> {
+
+ final Map<String, Object> propertiesInNewDef = (Map<String, Object>) ((Map<String, Object>) newTypeToUpdate.getValue()).get("properties");
+ final Map<String, Object> existingProperties =
+ (Map<String, Object>) ((Map<String, Object>) existingTypeContent.get(newTypeToUpdate.getKey())).get("properties");
- final Map<String, Object> typesYamlMap = (Map<String, Object>) new Yaml().load(typesYaml);
- final Set<String> typeYmlKeySet = typesYamlMap.keySet();
+ final List<Entry<String, Object>> propertiesMissingFromNewDef = MapUtils.isEmpty(existingProperties) ? Collections.emptyList()
+ : existingProperties.entrySet().stream()
+ .filter(existingPropEntry -> !propertiesInNewDef.keySet().contains(existingPropEntry.getKey()))
+ .collect(Collectors.toList());
- originalContent.forEach((key, value) -> {
- final Map<Object, Object> hashMap = new HashMap<>();
- if (typeYmlKeySet.contains(key)) {
- hashMap.put(key, typesYamlMap.get(key));
- } else {
- hashMap.put(key, value);
+ if (CollectionUtils.isNotEmpty(propertiesMissingFromNewDef)) {
+ typesToUpate.put(newTypeToUpdate.getKey(), newTypeToUpdate.getValue());
+
+ propertiesMissingFromNewDef
+ .forEach(existingPropToAdd -> propertiesInNewDef.put(existingPropToAdd.getKey(), existingPropToAdd.getValue()));
+ }
+ });
+ if (MapUtils.isNotEmpty(typesToUpate)) {
+ addTypesToDefaultImports(elementTypeEnum, new Yaml().dumpAsMap(typesToUpate), modelName);
}
- final String newContent = new YamlUtil().objectToYaml(hashMap);
- stringBuilder.append("\n").append(newContent);
- });
- return stringBuilder;
+ }
+ }
+
+ private Optional<ToscaImportByModel> getAdditionalTypes(final String modelName) {
+ 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());
}
}