2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.sdc.be.model.operations.impl;
23 import com.google.common.base.Strings;
24 import com.thinkaurelius.titan.graphdb.query.TitanPredicate;
25 import fj.data.Either;
26 import org.apache.commons.collections.CollectionUtils;
27 import org.apache.commons.lang3.tuple.ImmutablePair;
28 import org.apache.tinkerpop.gremlin.structure.Edge;
29 import org.openecomp.sdc.be.config.BeEcompErrorManager;
30 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
31 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
32 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
33 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
34 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
35 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
36 import org.openecomp.sdc.be.datatypes.elements.GroupTypeDataDefinition;
37 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
38 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
39 import org.openecomp.sdc.be.model.GroupTypeDefinition;
40 import org.openecomp.sdc.be.model.PropertyDefinition;
41 import org.openecomp.sdc.be.model.operations.StorageException;
42 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
43 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
44 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
45 import org.openecomp.sdc.be.resources.data.GroupTypeData;
46 import org.openecomp.sdc.be.resources.data.PropertyData;
47 import org.openecomp.sdc.be.resources.data.UniqueIdData;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 import org.springframework.beans.factory.annotation.Qualifier;
51 import org.springframework.stereotype.Component;
53 import javax.annotation.Resource;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.List;
58 import java.util.Optional;
60 import java.util.stream.Collectors;
62 import static org.openecomp.sdc.be.dao.titan.TitanUtils.buildNotInPredicate;
64 @Component("group-type-operation")
65 public class GroupTypeOperation extends AbstractOperation implements IGroupTypeOperation {
67 private CapabilityTypeOperation capabilityTypeOperation;
69 private static final Logger log = LoggerFactory.getLogger(GroupTypeOperation.class);
71 private static final String CREATE_FLOW_CONTEXT = "CreateGroupType";
72 private static final String GET_FLOW_CONTEXT = "GetGroupType";
74 private PropertyOperation propertyOperation;
76 private TitanGenericDao titanGenericDao;
78 public GroupTypeOperation(@Qualifier("titan-generic-dao") TitanGenericDao titanGenericDao, @Qualifier("property-operation") PropertyOperation propertyOperation) {
80 this.propertyOperation = propertyOperation;
81 this.titanGenericDao = titanGenericDao;
87 * @param titanGenericDao
89 public void setTitanGenericDao(TitanGenericDao titanGenericDao) {
90 this.titanGenericDao = titanGenericDao;
94 public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition) {
96 return addGroupType(groupTypeDefinition, false);
100 public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition, boolean inTransaction) {
102 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
106 Either<GroupTypeData, TitanOperationStatus> eitherStatus = addGroupTypeToGraph(groupTypeDefinition);
108 if (eitherStatus.isRight()) {
109 BeEcompErrorManager.getInstance().logBeFailedCreateNodeError(CREATE_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
110 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(eitherStatus.right().value()));
113 GroupTypeData groupTypeData = eitherStatus.left().value();
115 String uniqueId = groupTypeData.getUniqueId();
116 Either<GroupTypeDefinition, StorageOperationStatus> groupTypeRes = this.getGroupType(uniqueId, true);
118 if (groupTypeRes.isRight()) {
119 BeEcompErrorManager.getInstance().logBeFailedRetrieveNodeError(GET_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
121 List<CapabilityTypeDefinition> groupCapTypes = groupTypeDefinition.getCapabilityTypes();
122 if (!CollectionUtils.isEmpty(groupCapTypes)) {
123 Optional<TitanOperationStatus> firstFailure = connectToCapabilityType(groupTypeData, groupCapTypes);
124 if (firstFailure.isPresent()) {
125 groupTypeRes = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(firstFailure.get()));
130 result = groupTypeRes;
137 handleTransactionCommitRollback(inTransaction, result);
144 public Either<GroupTypeDefinition, StorageOperationStatus> upgradeGroupType(GroupTypeDefinition groupTypeDefinitionNew, GroupTypeDefinition groupTypeDefinitionOld) {
145 return upgradeGroupType(groupTypeDefinitionOld, groupTypeDefinitionNew, false);
149 public Either<GroupTypeDefinition, StorageOperationStatus> upgradeGroupType(GroupTypeDefinition groupTypeDefinitionNew, GroupTypeDefinition groupTypeDefinitionOld, boolean inTransaction) {
150 Either<GroupTypeDefinition, StorageOperationStatus> result = Either.left(groupTypeDefinitionNew);
154 // Right now upgrade Group is used only to ensure that already existing group type is connected by DERRIVED_FROM edge with it's parent
155 // We don't need to use for a while new node definition since following group type upgrade is not supported.
156 if (!Strings.isNullOrEmpty(groupTypeDefinitionOld.getDerivedFrom())) {
157 result = ensureExsitanceDerivedFromEdge(groupTypeDefinitionOld);
160 handleTransactionCommitRollback(inTransaction, result);
166 private Optional<TitanOperationStatus> connectToCapabilityType(GroupTypeData groupTypeData, List<CapabilityTypeDefinition> groupCapTypes) {
167 return groupCapTypes.stream()
168 .map(groupCapTypeDef -> connectTo(groupTypeData, groupCapTypeDef))
169 .filter(Either::isRight)
171 .map(either -> either.right().value());
174 private Either<GraphRelation, TitanOperationStatus> connectTo(GroupTypeData groupTypeData, CapabilityTypeDefinition groupCapTypeDef) {
175 Either<CapabilityTypeData, TitanOperationStatus> eitherCapData = capabilityTypeOperation.getCapabilityTypeByType(groupCapTypeDef.getType());
176 if (eitherCapData.isLeft()) {
177 return titanGenericDao.createRelation(groupTypeData, eitherCapData.left().value(), GraphEdgeLabels.GROUP_TYPE_CAPABILITY_TYPE, null);
180 return Either.right(eitherCapData.right().value());
183 public List<GroupTypeDefinition> getAllGroupTypes(Set<String> excludedGroupTypes) {
184 Map<String, Map.Entry<TitanPredicate, Object>> predicateCriteria = buildNotInPredicate(GraphPropertiesDictionary.TYPE.getProperty(), excludedGroupTypes);
185 List<GroupTypeData> groupTypes = titanGenericDao.getByCriteriaWithPredicate(NodeTypeEnum.GroupType, predicateCriteria, GroupTypeData.class)
187 .on(this::onTitanAccessError);
189 return convertGroupTypesToDefinition(groupTypes);
193 private List<GroupTypeDefinition> convertGroupTypesToDefinition(List<GroupTypeData> groupTypes) {
194 return groupTypes.stream()
195 .map(type -> new GroupTypeDefinition(type.getGroupTypeDataDefinition()))
196 .collect(Collectors.toList());
199 private List<GroupTypeData> onTitanAccessError(TitanOperationStatus toe) {
200 throw new StorageException(
201 DaoStatusConverter.convertTitanStatusToStorageStatus(toe));
205 public Either<GroupTypeDefinition, TitanOperationStatus> getGroupTypeByUid(String uniqueId) {
207 Either<GroupTypeDefinition, TitanOperationStatus> result = null;
209 Either<GroupTypeData, TitanOperationStatus> groupTypesRes = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), uniqueId, GroupTypeData.class);
211 if (groupTypesRes.isRight()) {
212 TitanOperationStatus status = groupTypesRes.right().value();
213 log.debug("Group type {} cannot be found in graph. status is {}", uniqueId, status);
214 return Either.right(status);
217 GroupTypeData gtData = groupTypesRes.left().value();
218 GroupTypeDefinition groupTypeDefinition = new GroupTypeDefinition(gtData.getGroupTypeDataDefinition());
220 TitanOperationStatus propertiesStatus = propertyOperation.fillProperties(uniqueId, NodeTypeEnum.GroupType, properList -> groupTypeDefinition.setProperties(properList));
222 if (propertiesStatus != TitanOperationStatus.OK) {
223 log.error("Failed to fetch properties of capability type {}", uniqueId);
224 return Either.right(propertiesStatus);
227 result = Either.left(groupTypeDefinition);
233 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId) {
235 return getGroupType(uniqueId, false);
240 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId, boolean inTransaction) {
241 return getElementType(this::getGroupTypeByUid, uniqueId, inTransaction);
245 public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type) {
246 return getLatestGroupTypeByType(type, false);
250 public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type, boolean inTransaction) {
251 Map<String, Object> mapCriteria = new HashMap<>();
252 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
253 mapCriteria.put(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty(), true);
255 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
259 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByCriteria(String type, Map<String, Object> properties, boolean inTransaction) {
260 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
262 if (type == null || type.isEmpty()) {
263 log.error("type is empty");
264 result = Either.right(StorageOperationStatus.INVALID_ID);
268 Either<List<GroupTypeData>, TitanOperationStatus> groupTypeEither = titanGenericDao.getByCriteria(NodeTypeEnum.GroupType, properties, GroupTypeData.class);
269 if (groupTypeEither.isRight()) {
270 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(groupTypeEither.right().value()));
272 GroupTypeDataDefinition dataDefinition = groupTypeEither.left().value().stream().map(e -> e.getGroupTypeDataDefinition()).findFirst().get();
273 result = getGroupType(dataDefinition.getUniqueId(), inTransaction);
279 handleTransactionCommitRollback(inTransaction, result);
284 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version) {
285 return getGroupTypeByTypeAndVersion(type, version, false);
289 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version, boolean inTransaction) {
290 Map<String, Object> mapCriteria = new HashMap<>();
291 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
292 mapCriteria.put(GraphPropertiesDictionary.VERSION.getProperty(), version);
294 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
298 * Add group type to graph.
300 * 1. Add group type node
302 * 2. Add edge between the former node to its parent(if exists)
304 * 3. Add property node and associate it to the node created at #1. (per property & if exists)
306 * @param groupTypeDefinition
309 private Either<GroupTypeData, TitanOperationStatus> addGroupTypeToGraph(GroupTypeDefinition groupTypeDefinition) {
311 log.debug("Got group type {}", groupTypeDefinition);
313 String ctUniqueId = UniqueIdBuilder.buildGroupTypeUid(groupTypeDefinition.getType(), groupTypeDefinition.getVersion());
315 GroupTypeData groupTypeData = buildGroupTypeData(groupTypeDefinition, ctUniqueId);
317 log.debug("Before adding group type to graph. groupTypeData = {}", groupTypeData);
319 Either<GroupTypeData, TitanOperationStatus> createGTResult = titanGenericDao.createNode(groupTypeData, GroupTypeData.class);
320 log.debug("After adding group type to graph. status is = {}", createGTResult);
322 if (createGTResult.isRight()) {
323 TitanOperationStatus operationStatus = createGTResult.right().value();
324 log.error("Failed to add group type {} to graph. status is {}", groupTypeDefinition.getType(), operationStatus);
325 return Either.right(operationStatus);
328 GroupTypeData resultCTD = createGTResult.left().value();
329 List<PropertyDefinition> properties = groupTypeDefinition.getProperties();
330 Either<Map<String, PropertyData>, TitanOperationStatus> addPropertiesToCapablityType = propertyOperation.addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.GroupType, properties);
331 if (addPropertiesToCapablityType.isRight()) {
332 log.error("Failed add properties {} to capability {}", properties, groupTypeDefinition.getType());
333 return Either.right(addPropertiesToCapablityType.right().value());
336 String derivedFrom = groupTypeDefinition.getDerivedFrom();
337 if (derivedFrom != null) {
338 Either<GraphRelation, TitanOperationStatus> createRelation = connectToDerivedFrom(ctUniqueId, derivedFrom);
339 if (createRelation.isRight()) {
340 return Either.right(createRelation.right().value());
344 return Either.left(createGTResult.left().value());
349 private Either<GraphRelation, TitanOperationStatus> connectToDerivedFrom(String ctUniqueId, String derivedFrom) {
350 log.debug("Before creating relation between Group Type with id {} to its parent {}", ctUniqueId, derivedFrom);
352 Either<GroupTypeData, TitanOperationStatus> derivedFromGroupTypeResult =
353 titanGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), derivedFrom, GroupTypeData.class);
355 if (derivedFromGroupTypeResult.isLeft()) {
356 UniqueIdData from = new UniqueIdData(NodeTypeEnum.GroupType, ctUniqueId);
357 GroupTypeData to = derivedFromGroupTypeResult.left().value();
359 Either<GraphRelation, TitanOperationStatus> createRelation = titanGenericDao.createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null);
360 log.debug("After create relation between Group Type with id {} to its parent {}, status is {}.", ctUniqueId, derivedFrom, createRelation);
361 return createRelation;
363 TitanOperationStatus status = derivedFromGroupTypeResult.right().value();
364 log.debug("Failed to found parent Group Type {}, stauts is {}.", derivedFrom, status);
365 return Either.right(status);
370 private Either<GroupTypeDefinition, StorageOperationStatus> ensureExsitanceDerivedFromEdge(GroupTypeDefinition groupTypeDefinition) {
371 Either<GroupTypeDefinition, StorageOperationStatus> result = Either.left(groupTypeDefinition);
373 GroupTypeData childGroupType = null;
374 GroupTypeData parentGroupType = null;
376 Either<GroupTypeData, TitanOperationStatus> childGroupTypeResult =
377 titanGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), groupTypeDefinition.getType(), GroupTypeData.class);
378 if (childGroupTypeResult.isRight()) {
379 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(childGroupTypeResult.right().value()));
380 log.debug("Filed to find GroupType with type {}, status is {}.", groupTypeDefinition.getType(), childGroupTypeResult);
382 childGroupType = childGroupTypeResult.left().value();
386 if (result.isLeft()) {
387 Either<GroupTypeData, TitanOperationStatus> parentGroupTypeResult =
388 titanGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), groupTypeDefinition.getDerivedFrom(), GroupTypeData.class);
389 if (parentGroupTypeResult.isRight()) {
390 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(parentGroupTypeResult.right().value()));
391 log.debug("Filed to find GroupType with type {}, status is {}.", groupTypeDefinition.getDerivedFrom(), parentGroupTypeResult);
393 parentGroupType = parentGroupTypeResult.left().value();
398 if (childGroupType != null && parentGroupType != null) {
399 Either<Edge, TitanOperationStatus> edgeDerivedFromResult = titanGenericDao.getEdgeByNodes(childGroupType, parentGroupType, GraphEdgeLabels.DERIVED_FROM);
400 if (edgeDerivedFromResult.isLeft()) {
401 log.debug("It was found relation {}. Don't need to create the edge.", edgeDerivedFromResult.left().value());
403 Either<GraphRelation, TitanOperationStatus> createRelationResult = titanGenericDao.createRelation(childGroupType, parentGroupType, GraphEdgeLabels.DERIVED_FROM, null);
404 log.debug("After create relation between Group Type with id {} to its parent with id {}, status is {}.",
405 childGroupType.getKeyValueId().getValue(), parentGroupType.getKeyValueId().getValue(), createRelationResult);
406 if (createRelationResult.isRight()) {
407 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(createRelationResult.right().value()));
418 private GroupTypeData buildGroupTypeData(GroupTypeDefinition groupTypeDefinition, String ctUniqueId) {
420 GroupTypeData groupTypeData = new GroupTypeData(groupTypeDefinition);
422 groupTypeData.getGroupTypeDataDefinition().setUniqueId(ctUniqueId);
423 Long creationDate = groupTypeData.getGroupTypeDataDefinition().getCreationTime();
424 if (creationDate == null) {
425 creationDate = System.currentTimeMillis();
427 groupTypeData.getGroupTypeDataDefinition().setCreationTime(creationDate);
428 groupTypeData.getGroupTypeDataDefinition().setModificationTime(creationDate);
430 return groupTypeData;
433 public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
434 Map<String, Object> propertiesToMatch = new HashMap<String, Object>();
435 propertiesToMatch.put(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childCandidateType);
436 Either<List<CapabilityTypeData>, TitanOperationStatus> getResponse = titanGenericDao.getByCriteria(NodeTypeEnum.CapabilityType, propertiesToMatch, CapabilityTypeData.class);
437 if (getResponse.isRight()) {
438 TitanOperationStatus titanOperationStatus = getResponse.right().value();
439 log.debug("Couldn't fetch capability type {}, error: {}", childCandidateType, titanOperationStatus);
440 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
442 String childUniqueId = getResponse.left().value().get(0).getUniqueId();
443 Set<String> travelledTypes = new HashSet<>();
445 travelledTypes.add(childUniqueId);
446 Either<List<ImmutablePair<CapabilityTypeData, GraphEdge>>, TitanOperationStatus> childrenNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childUniqueId, GraphEdgeLabels.DERIVED_FROM,
447 NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
448 if (childrenNodes.isRight()) {
449 if (childrenNodes.right().value() != TitanOperationStatus.NOT_FOUND) {
450 TitanOperationStatus titanOperationStatus = getResponse.right().value();
451 log.debug("Couldn't fetch derived from node for capability type {}, error: {}", childCandidateType, titanOperationStatus);
452 return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
454 log.debug("Derived from node is not found for type {} - this is OK for root capability.");
455 return Either.left(false);
458 String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
459 if (derivedFromUniqueId.equals(parentCandidateType)) {
460 log.debug("Verified that capability type {} derives from capability type {}", childCandidateType, parentCandidateType);
461 return Either.left(true);
463 childUniqueId = derivedFromUniqueId;
464 } while (!travelledTypes.contains(childUniqueId));
465 // this stop condition should never be used, if we use it, we have an
466 // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
467 // It's here just to avoid infinite loop in case we have such cycle.
468 log.error("Detected a cycle of \"derived from\" edges starting at capability type node {}", childUniqueId);
469 return Either.right(StorageOperationStatus.GENERAL_ERROR);
475 * @param propertyOperation
477 public void setPropertyOperation(PropertyOperation propertyOperation) {
478 this.propertyOperation = propertyOperation;
482 public Either<GroupTypeData, TitanOperationStatus> getLatestGroupTypeByNameFromGraph(String name) {