7d01f3f273226cdb5e83314eac0b6f098be1cc6f
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / DataTypeOperation.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19 package org.openecomp.sdc.be.model.operations.impl;
20
21 import fj.data.Either;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Optional;
29 import org.apache.commons.collections.CollectionUtils;
30 import org.apache.commons.collections4.MapUtils;
31 import org.apache.commons.lang.StringUtils;
32 import org.apache.commons.lang3.tuple.ImmutableTriple;
33 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
34 import org.apache.tinkerpop.gremlin.structure.Vertex;
35 import org.janusgraph.core.JanusGraph;
36 import org.openecomp.sdc.be.config.BeEcompErrorManager;
37 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
38 import org.openecomp.sdc.be.dao.api.ActionStatus;
39 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao;
40 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
41 import org.openecomp.sdc.be.dao.janusgraph.QueryType;
42 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
43 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
44 import org.openecomp.sdc.be.datatypes.elements.DataTypeDataDefinition;
45 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
46 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
47 import org.openecomp.sdc.be.exception.supplier.DataTypeOperationExceptionSupplier;
48 import org.openecomp.sdc.be.model.DataTypeDefinition;
49 import org.openecomp.sdc.be.model.PropertyDefinition;
50 import org.openecomp.sdc.be.model.dto.PropertyDefinitionDto;
51 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException;
52 import org.openecomp.sdc.be.model.mapper.PropertyDefinitionDtoMapper;
53 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
54 import org.openecomp.sdc.be.resources.data.DataTypeData;
55 import org.openecomp.sdc.be.resources.data.PropertyData;
56 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.springframework.beans.factory.annotation.Autowired;
60 import org.springframework.stereotype.Component;
61
62 @Component("dataType-operation")
63 public class DataTypeOperation extends AbstractOperation {
64
65     private static final Logger LOGGER = LoggerFactory.getLogger(DataTypeOperation.class);
66
67     private ModelOperation modelOperation;
68     private PropertyOperation propertyOperation;
69
70     @Autowired
71     public DataTypeOperation(final HealingJanusGraphGenericDao janusGraphGenericDao) {
72         this.janusGraphGenericDao = janusGraphGenericDao;
73     }
74
75     //circular dependency ModelOperation->ModelElementOperation->DataTypeOperation
76     @Autowired
77     public void setModelOperation(final ModelOperation modelOperation) {
78         this.modelOperation = modelOperation;
79     }
80
81     @Autowired
82     public void setPropertyOperation(PropertyOperation propertyOperation) {
83         this.propertyOperation = propertyOperation;
84     }
85
86     public List<DataTypeData> getAllDataTypeNodes() {
87         final List<DataTypeData> dataTypesFound = new ArrayList<>();
88         final Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypesWithNullModel =
89             janusGraphGenericDao.getByCriteria(NodeTypeEnum.DataType, null, DataTypeData.class);
90
91         final var dataTypesValidated = validateDataType(getAllDataTypesWithNullModel, null);
92         if (CollectionUtils.isNotEmpty(dataTypesValidated)) {
93             dataTypesFound.addAll(dataTypesValidated);
94         }
95
96         final List<DataTypeData> allDataTypeNodesWithModel = getAllDataTypesWithModel();
97         if (CollectionUtils.isNotEmpty(allDataTypeNodesWithModel)) {
98             dataTypesFound.addAll(allDataTypeNodesWithModel);
99         }
100         return dataTypesFound;
101     }
102
103     public Map<String, List<String>> getAllDataTypeUidsToModels() {
104         final Map<String, List<String>> dataTypesFound = new HashMap<>();
105         final Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypesWithNullModel =
106             janusGraphGenericDao.getByCriteria(NodeTypeEnum.DataType, null, DataTypeData.class);
107
108         final var dataTypesValidated = validateDataType(getAllDataTypesWithNullModel, null);
109
110         for (DataTypeData dataType : dataTypesValidated) {
111             if (!dataTypesFound.containsKey(dataType.getUniqueId())) {
112                 dataTypesFound.put(dataType.getUniqueId(), new ArrayList<>());
113             }
114             dataTypesFound.get(dataType.getUniqueId()).add(null);
115         }
116
117         modelOperation.findAllModels()
118             .forEach(model -> {
119                 for (DataTypeData dataType : getAllDataTypesWithModel(model.getName())) {
120                     if (!dataTypesFound.containsKey(dataType.getUniqueId())) {
121                         dataTypesFound.put(dataType.getUniqueId(), new ArrayList<>());
122                     }
123                     dataTypesFound.get(dataType.getUniqueId()).add(model.getName());
124                 }
125             });
126         return dataTypesFound;
127     }
128
129     public List<String> getAllDataTypeModels(final String dataTypeName) {
130         final List<String> models = new ArrayList<>();
131         ImmutableTriple<QueryType, String, Object> criteria =
132             new ImmutableTriple<>(QueryType.HAS, GraphPropertiesDictionary.NAME.getProperty(), dataTypeName);
133
134         final Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypesForModel =
135             janusGraphGenericDao.getByCriteria(NodeTypeEnum.DataType, DataTypeData.class, List.of(criteria));
136         final var dataTypesValidated = validateDataType(getAllDataTypesForModel, null);
137         for (DataTypeData dataType : dataTypesValidated) {
138             models.add(dataType.getDataTypeDataDefinition().getModel());
139         }
140         return models;
141     }
142
143     private List<DataTypeData> getAllDataTypesWithModel(final String modelName) {
144         final Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypesByModel = janusGraphGenericDao
145             .getByCriteriaForModel(NodeTypeEnum.DataType, null, modelName, DataTypeData.class);
146         return validateDataType(getAllDataTypesByModel, modelName);
147     }
148
149     private List<DataTypeData> getAllDataTypesWithModel() {
150         final List<DataTypeData> dataTypesWithModel = new ArrayList<>();
151         modelOperation.findAllModels()
152             .forEach(model -> {
153                 final var modelName = model.getName();
154                 final Either<List<DataTypeData>, JanusGraphOperationStatus> getAllDataTypesByModel = janusGraphGenericDao
155                     .getByCriteriaForModel(NodeTypeEnum.DataType, null, modelName, DataTypeData.class);
156                 final var dataTypesValidated = validateDataType(getAllDataTypesByModel, modelName);
157                 dataTypesWithModel.addAll(dataTypesValidated);
158             });
159         return dataTypesWithModel;
160     }
161
162     private List<DataTypeData> validateDataType(final Either<List<DataTypeData>, JanusGraphOperationStatus> getDataTypes, final String modelName) {
163         if (getDataTypes.isRight() && getDataTypes.right().value() == JanusGraphOperationStatus.NOT_FOUND) {
164             return Collections.emptyList();
165         }
166         if (getDataTypes.isRight()) {
167             final var status = getDataTypes.right().value();
168             if (LOGGER.isErrorEnabled()) {
169                 final var errorMsg = String.format("Failed to fetch data types from database with model %s. Status is %s", modelName, status);
170                 LOGGER.error(String.valueOf(EcompLoggerErrorCode.UNKNOWN_ERROR), DataTypeOperation.class.getName(), errorMsg);
171                 BeEcompErrorManager.getInstance().logInternalConnectionError(DataTypeOperation.class.getName(), errorMsg, ErrorSeverity.ERROR);
172             }
173             return Collections.emptyList();
174         }
175         return getDataTypes.left().value();
176     }
177
178     public void deleteDataTypesByModelId(final String modelId) {
179         final JanusGraph janusGraph = janusGraphGenericDao.getJanusGraph();
180         final GraphTraversalSource traversal = janusGraph.traversal();
181         final List<Vertex> dataTypeList = traversal.V()
182             .has(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), modelId)
183             .out(GraphEdgeLabels.MODEL_ELEMENT.getProperty())
184             .has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.DataType.getName())
185             .toList();
186         dataTypeList.forEach(dataTypeVertex -> {
187             traversal.V(dataTypeVertex).out(GraphEdgeLabels.PROPERTY.getProperty()).drop().iterate();
188             dataTypeVertex.remove();
189         });
190     }
191
192     public Optional<DataTypeDataDefinition> getDataTypeByUid(final String uniqueId) {
193         final Either<DataTypeData, JanusGraphOperationStatus> dataTypeEither = janusGraphGenericDao
194             .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.DataType), uniqueId, DataTypeData.class);
195         if (dataTypeEither.isRight()) {
196             if (JanusGraphOperationStatus.NOT_FOUND.equals(dataTypeEither.right().value())) {
197                 return Optional.empty();
198             }
199             final StorageOperationStatus storageOperationStatus
200                 = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(dataTypeEither.right().value());
201             LOGGER.warn("Failed to fetch data type '{}' from JanusGraph. Status is: {}", uniqueId, storageOperationStatus);
202             throw new OperationException(ActionStatus.GENERAL_ERROR,
203                 String.format("Failed to fetch data type '%s' from JanusGraph. Status is: %s", uniqueId, storageOperationStatus));
204         }
205         return Optional.of(dataTypeEither.left().value().getDataTypeDataDefinition());
206     }
207
208     public Optional<DataTypeDataDefinition> getDataTypeByNameAndModel(final String name, String model) {
209         final Either<DataTypeData, JanusGraphOperationStatus> dataTypeEither = janusGraphGenericDao
210             .getNode("name", name, DataTypeData.class, model);
211         if (dataTypeEither.isRight()) {
212             if (JanusGraphOperationStatus.NOT_FOUND.equals(dataTypeEither.right().value())) {
213                 return Optional.empty();
214             }
215             final StorageOperationStatus storageOperationStatus
216                 = DaoStatusConverter.convertJanusGraphStatusToStorageStatus(dataTypeEither.right().value());
217             LOGGER.warn("Failed to fetch data type '{}' from JanusGraph. Status is: {}", name, storageOperationStatus);
218             throw new OperationException(ActionStatus.GENERAL_ERROR,
219                 String.format("Failed to fetch data type '%s' from JanusGraph. Status is: %s", name, storageOperationStatus));
220         }
221         return Optional.of(dataTypeEither.left().value().getDataTypeDataDefinition());
222     }
223
224     public List<PropertyDefinition> findAllProperties(final String uniqueId) {
225         final Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> propertiesEither =
226             propertyOperation.findPropertiesOfNode(NodeTypeEnum.DataType, uniqueId);
227         if (propertiesEither.isRight()) {
228             final JanusGraphOperationStatus status = propertiesEither.right().value();
229             if (status == JanusGraphOperationStatus.NOT_FOUND) {
230                 return List.of();
231             }
232             LOGGER.error("Could not retrieve data type '{}' properties. JanusGraphOperationStatus: '{}'", uniqueId, status);
233
234             throw DataTypeOperationExceptionSupplier.unexpectedErrorWhileFetchingProperties(uniqueId).get();
235         }
236         final Map<String, PropertyDefinition> propertyMap = propertiesEither.left().value();
237         if (MapUtils.isEmpty(propertyMap)) {
238             return List.of();
239         }
240         final List<PropertyDefinition> propertyDefinitions = new ArrayList<>(propertyMap.values());
241         propertyDefinitions.sort(Comparator.comparing(PropertyDefinition::getName));
242         return propertyDefinitions;
243     }
244
245     public Optional<DataTypeDefinition> handleDataTypeDownloadRequestById(final String dataTypeId) {
246         if (StringUtils.isNotEmpty(dataTypeId)) {
247             Optional<DataTypeDataDefinition> dataTypeDataDefinition = getDataTypeByUid(dataTypeId);
248             if (dataTypeDataDefinition.isPresent()) {
249                 DataTypeDefinition dataTypeDefinition = new DataTypeDefinition(dataTypeDataDefinition.get());
250                 dataTypeDefinition.setProperties(findAllProperties(dataTypeId));
251                 return Optional.of(dataTypeDefinition);
252             }
253         }
254         return Optional.empty();
255     }
256
257     public PropertyDefinitionDto createProperty(final String dataTypeId, final PropertyDefinitionDto propertyDefinitionDto) {
258         final String propertyName = propertyDefinitionDto.getName();
259         LOGGER.debug("Adding property '{}' to data type '{}'.", propertyName, dataTypeId);
260
261         getDataTypeByUid(dataTypeId).orElseThrow(DataTypeOperationExceptionSupplier.dataTypeNotFound(dataTypeId));
262
263         final Either<PropertyData, JanusGraphOperationStatus> resultEither =
264             propertyOperation.addPropertyToNodeType(propertyName, PropertyDefinitionDtoMapper.mapTo(propertyDefinitionDto),
265                 NodeTypeEnum.DataType, dataTypeId, false);
266         if (resultEither.isRight()) {
267             final JanusGraphOperationStatus status = resultEither.right().value();
268             LOGGER.debug("Could not create property '{}' on data type '{}'. JanusGraph status is '{}'", propertyName, dataTypeId, status);
269             if (status == JanusGraphOperationStatus.JANUSGRAPH_SCHEMA_VIOLATION) {
270                 throw DataTypeOperationExceptionSupplier.dataTypePropertyAlreadyExists(dataTypeId, propertyName).get();
271             }
272             LOGGER.error("Could not create property '{}' on data type '{}'. JanusGraph status is '{}'", propertyName, dataTypeId, status);
273             throw DataTypeOperationExceptionSupplier.unexpectedErrorWhileCreatingProperty(dataTypeId, propertyName).get();
274         }
275         LOGGER.debug("Property '{}' was added to data type '{}'.", propertyName, dataTypeId);
276         final PropertyData propertyData = resultEither.left().value();
277         final PropertyDataDefinition propertyDataDefinition = propertyData.getPropertyDataDefinition();
278         propertyDataDefinition.setName(propertyName);
279         return PropertyDefinitionDtoMapper.mapFrom(propertyDataDefinition);
280     }
281
282 }