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 org.janusgraph.graphdb.query.JanusGraphPredicate;
25 import fj.data.Either;
26 import org.apache.commons.collections.CollectionUtils;
27 import org.apache.commons.collections.MapUtils;
28 import org.apache.commons.lang.StringUtils;
29 import org.apache.commons.lang3.tuple.ImmutablePair;
30 import org.openecomp.sdc.be.config.BeEcompErrorManager;
31 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
32 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
33 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
34 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
35 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
36 import org.openecomp.sdc.be.dao.neo4j.GraphEdgePropertiesDictionary;
37 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
38 import org.openecomp.sdc.be.datatypes.elements.GroupTypeDataDefinition;
39 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
40 import org.openecomp.sdc.be.model.CapabilityDefinition;
41 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
42 import org.openecomp.sdc.be.model.GroupTypeDefinition;
43 import org.openecomp.sdc.be.model.PropertyDefinition;
44 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
45 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
46 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
47 import org.openecomp.sdc.be.model.operations.api.TypeOperations;
48 import org.openecomp.sdc.be.model.utils.TypeCompareUtils;
49 import org.openecomp.sdc.be.resources.data.*;
50 import org.openecomp.sdc.common.log.wrappers.Logger;
51 import org.springframework.stereotype.Component;
54 import java.util.function.Function;
55 import java.util.stream.Collectors;
57 import static org.openecomp.sdc.be.dao.janusgraph.JanusGraphUtils.buildNotInPredicate;
59 @Component("group-type-operation")
60 public class GroupTypeOperation implements IGroupTypeOperation {
62 private static final Logger log = Logger.getLogger(GroupTypeOperation.class.getName());
63 private static final String CREATE_FLOW_CONTEXT = "CreateGroupType";
65 private final PropertyOperation propertyOperation;
66 private final JanusGraphGenericDao janusGraphGenericDao;
67 private final CapabilityTypeOperation capabilityTypeOperation;
68 private final CapabilityOperation capabilityOperation;
69 private final DerivedFromOperation derivedFromOperation;
70 private final OperationUtils operationUtils;
73 public GroupTypeOperation(JanusGraphGenericDao janusGraphGenericDao,
74 PropertyOperation propertyOperation,
75 CapabilityTypeOperation capabilityTypeOperation,
76 CapabilityOperation capabilityOperation,
77 DerivedFromOperation derivedFromOperation, OperationUtils operationUtils) {
78 this.janusGraphGenericDao = janusGraphGenericDao;
79 this.propertyOperation = propertyOperation;
80 this.capabilityTypeOperation = capabilityTypeOperation;
81 this.capabilityOperation = capabilityOperation;
82 this.derivedFromOperation = derivedFromOperation;
83 this.operationUtils = operationUtils;
87 public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition) {
88 Either<GroupTypeDefinition, StorageOperationStatus> validationRes = validateUpdateProperties(groupTypeDefinition);
89 if (validationRes.isRight()) {
90 log.error("#addGroupType - One or all properties of group type {} not valid. status is {}", groupTypeDefinition, validationRes.right().value());
94 return addGroupType(groupTypeDefinition, true);
98 public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition, boolean inTransaction) {
100 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
104 Either<GroupTypeData, JanusGraphOperationStatus> eitherStatus = addGroupTypeToGraph(groupTypeDefinition);
106 if (eitherStatus.isRight()) {
107 BeEcompErrorManager.getInstance().logBeFailedCreateNodeError(CREATE_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
108 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(eitherStatus.right().value()));
111 result = getGroupType(eitherStatus.left().value().getUniqueId(), inTransaction);
117 janusGraphGenericDao.handleTransactionCommitRollback(inTransaction, result);
123 public Either<GroupTypeDefinition, StorageOperationStatus> updateGroupType(GroupTypeDefinition updatedGroupType, GroupTypeDefinition currGroupType) {
124 log.debug("updating group type {}", updatedGroupType.getType());
125 return updateGroupTypeOnGraph(updatedGroupType, currGroupType);
129 public Either<GroupTypeDefinition, StorageOperationStatus> validateUpdateProperties(GroupTypeDefinition groupTypeDefinition) {
130 JanusGraphOperationStatus error = null;
131 if (CollectionUtils.isNotEmpty(groupTypeDefinition.getProperties()) && !Strings.isNullOrEmpty(groupTypeDefinition.getDerivedFrom())) {
132 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> allPropertiesRes =
133 getAllGroupTypePropertiesFromAllDerivedFrom(groupTypeDefinition.getDerivedFrom());
134 if (allPropertiesRes.isRight() && !allPropertiesRes.right().value().equals(
135 JanusGraphOperationStatus.NOT_FOUND)) {
136 error = allPropertiesRes.right().value();
137 log.debug("Couldn't fetch derived from property nodes for group type {}, error: {}", groupTypeDefinition.getType(), error);
139 if (error == null && !allPropertiesRes.left().value().isEmpty()) {
140 Either<List<PropertyDefinition>, JanusGraphOperationStatus> validatePropertiesRes = propertyOperation.validatePropertiesUniqueness(allPropertiesRes.left().value(),
141 groupTypeDefinition.getProperties());
142 if (validatePropertiesRes.isRight()) {
143 error = validatePropertiesRes.right().value();
148 return Either.left(groupTypeDefinition);
150 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error));
153 private Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> getAllGroupTypePropertiesFromAllDerivedFrom(String firstParentType) {
154 return janusGraphGenericDao
155 .getNode(GraphPropertiesDictionary.TYPE.getProperty(), firstParentType, GroupTypeData.class)
157 .bind(parentGroup -> propertyOperation.getAllTypePropertiesFromAllDerivedFrom(parentGroup.getUniqueId(), NodeTypeEnum.GroupType, GroupTypeData.class));
161 private StorageOperationStatus mergeCapabilities(GroupTypeDefinition groupTypeDef) {
162 Map<String, CapabilityDefinition> updatedGroupTypeCapabilities = groupTypeDef.getCapabilities();
163 Map<String, CapabilityDefinition> newGroupTypeCapabilities;
164 Either<List<CapabilityDefinition>, StorageOperationStatus> oldCapabilitiesRes = getCapablities(groupTypeDef.getUniqueId());
165 if (oldCapabilitiesRes.isRight()) {
166 StorageOperationStatus status = oldCapabilitiesRes.right().value();
167 if (status == StorageOperationStatus.NOT_FOUND) {
168 newGroupTypeCapabilities = updatedGroupTypeCapabilities;
175 Map<String, CapabilityDefinition> oldCapabilities = asCapabilitiesMap(oldCapabilitiesRes.left().value());
176 newGroupTypeCapabilities = collectNewCapabilities(updatedGroupTypeCapabilities, oldCapabilities);
178 for(Map.Entry<String, CapabilityDefinition> oldEntry: oldCapabilities.entrySet()) {
179 String key = oldEntry.getKey();
180 CapabilityDefinition newCapDef = updatedGroupTypeCapabilities != null? updatedGroupTypeCapabilities.get(key): null;
181 CapabilityDefinition oldCapDef = oldEntry.getValue();
183 StorageOperationStatus deleteCapResult = deleteOutdatedCapability(newGroupTypeCapabilities, newCapDef, oldCapDef);
184 if(deleteCapResult != StorageOperationStatus.OK) {
185 return deleteCapResult;
190 JanusGraphOperationStatus createCapResult = createCapabilities(new GroupTypeData(groupTypeDef), newGroupTypeCapabilities);
191 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createCapResult);
195 * @param newGroupTypeCapabilities
200 private StorageOperationStatus deleteOutdatedCapability(Map<String, CapabilityDefinition> newGroupTypeCapabilities, CapabilityDefinition newCapDef, CapabilityDefinition oldCapDef) {
201 if(!isUpdateAllowed(newCapDef, oldCapDef)) {
202 return StorageOperationStatus.MATCH_NOT_FOUND;
205 if (!TypeCompareUtils.capabilityEquals(oldCapDef, newCapDef)) {
206 StorageOperationStatus deleteCapResult = capabilityOperation.deleteCapability(oldCapDef);
208 if(deleteCapResult == StorageOperationStatus.OK) {
209 newGroupTypeCapabilities.put(newCapDef.getName(), newCapDef);
212 return deleteCapResult;
216 return StorageOperationStatus.OK;
219 private boolean isUpdateAllowed(CapabilityDefinition newCapDef, CapabilityDefinition oldCapDef) {
220 if (newCapDef == null) {
221 log.error("#upsertCapabilities - Failed due to attempt to delete the capability with id {}", oldCapDef.getUniqueId());
225 if (newCapDef.getType() == null || !newCapDef.getType().equals(oldCapDef.getType())) {
226 log.error("#upsertCapabilities - Failed due to attempt to change type of the capability with id {}", oldCapDef.getUniqueId());
234 * @param updatedGroupTypeCapabilities
235 * @param oldCapabilities
238 private Map<String, CapabilityDefinition> collectNewCapabilities(Map<String, CapabilityDefinition> updatedGroupTypeCapabilities, Map<String, CapabilityDefinition> oldCapabilities) {
239 return updatedGroupTypeCapabilities != null? updatedGroupTypeCapabilities.entrySet().stream()
240 .filter(entry -> !oldCapabilities.containsKey(entry.getKey()))
241 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue) ): null;
244 private JanusGraphOperationStatus createCapabilities(GroupTypeData groupTypeData, Map<String, CapabilityDefinition> groupCapabilities) {
245 if (MapUtils.isEmpty(groupCapabilities)) {
246 return JanusGraphOperationStatus.OK;
249 return groupCapabilities.values().stream()
250 .map(v -> createCapability(groupTypeData, v))
251 .filter(Either::isRight)
253 .map(either -> either.right().value())
254 .orElse(JanusGraphOperationStatus.OK);
257 private Either<GraphRelation, JanusGraphOperationStatus> createCapability(GroupTypeData groupTypeData, CapabilityDefinition capabilityDef) {
258 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> eitherCapData = capabilityTypeOperation.getCapabilityTypeByType(capabilityDef.getType());
261 .map(CapabilityTypeData::new)
263 .bind(capTypeData -> capabilityOperation.addCapabilityToGraph(groupTypeData.getUniqueId(), capTypeData, capabilityDef))
265 .bind(capData -> connectToCapability(groupTypeData, capData, capabilityDef.getName()));
270 * Get capability with all relevant properties
274 private Either<List<CapabilityDefinition>, StorageOperationStatus> getCapablities(String groupTypeId) {
275 Either<List<ImmutablePair<CapabilityData, GraphEdge>>, JanusGraphOperationStatus> groupCapabilitiesOnGraph =
276 janusGraphGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), groupTypeId, GraphEdgeLabels.GROUP_TYPE_CAPABILITY, NodeTypeEnum.Capability, CapabilityData.class, true);
278 if (groupCapabilitiesOnGraph.isRight()) {
279 JanusGraphOperationStatus capabilityStatus = groupCapabilitiesOnGraph.right().value();
280 if (capabilityStatus == JanusGraphOperationStatus.NOT_FOUND) {
281 return Either.left(Collections.emptyList());
283 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(capabilityStatus));
286 List<ImmutablePair<CapabilityData, GraphEdge>> groupCapabilites = groupCapabilitiesOnGraph.left().value();
287 groupCapabilites.forEach(this::fillCapabilityName);
289 return capabilityOperation.getCapabilitiesWithProps(groupCapabilites)
291 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
294 private void fillCapabilityName(ImmutablePair<CapabilityData, GraphEdge> pair) {
295 pair.getLeft().getCapabilityDataDefinition().setName((String)pair.getRight().getProperties().get(GraphEdgePropertiesDictionary.NAME.getProperty()));
298 private Either<GraphRelation, JanusGraphOperationStatus> connectToCapability(GroupTypeData groupTypeData, CapabilityData capabilityData, String capabilityName) {
299 Map<String, Object> properties = new HashMap<>();
300 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), capabilityName);
302 return janusGraphGenericDao.createRelation(groupTypeData, capabilityData, GraphEdgeLabels.GROUP_TYPE_CAPABILITY, properties);
306 public List<GroupTypeDefinition> getAllGroupTypes(Set<String> excludedGroupTypes) {
307 Map<String, Map.Entry<JanusGraphPredicate, Object>> predicateCriteria = buildNotInPredicate(GraphPropertiesDictionary.TYPE.getProperty(), excludedGroupTypes);
308 List<GroupTypeData> groupTypes = janusGraphGenericDao
309 .getByCriteriaWithPredicate(NodeTypeEnum.GroupType, predicateCriteria, GroupTypeData.class)
311 .on(operationUtils::onJanusGraphOperationFailure);
312 return convertGroupTypesToDefinition(groupTypes);
316 private List<GroupTypeDefinition> convertGroupTypesToDefinition(List<GroupTypeData> groupTypes) {
317 return groupTypes.stream()
318 .map(type -> new GroupTypeDefinition(type.getGroupTypeDataDefinition()))
319 .collect(Collectors.toList());
323 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByUid(String uniqueId) {
324 log.debug("#getGroupTypeByUid - fetching group type with id {}", uniqueId);
325 return janusGraphGenericDao
326 .getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), uniqueId, GroupTypeData.class)
328 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus)
330 .bind(groupType -> buildGroupTypeDefinition(uniqueId, groupType));
334 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId, boolean inTransaction) {
335 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
338 Either<GroupTypeDefinition, StorageOperationStatus> ctResult = getGroupTypeByUid(uniqueId);
340 if (ctResult.isRight()) {
341 StorageOperationStatus status = ctResult.right().value();
342 if (status != StorageOperationStatus.NOT_FOUND) {
343 log.error("Failed to retrieve information on element uniqueId: {}. status is {}", uniqueId, status);
345 result = Either.right(ctResult.right().value());
349 result = Either.left(ctResult.left().value());
353 janusGraphGenericDao.handleTransactionCommitRollback(inTransaction, result);
359 public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type) {
360 return getLatestGroupTypeByType(type, true);
364 public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type, boolean inTransaction) {
365 Map<String, Object> mapCriteria = new HashMap<>();
366 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
367 mapCriteria.put(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty(), true);
369 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
373 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByCriteria(String type, Map<String, Object> properties, boolean inTransaction) {
374 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
376 if (type == null || type.isEmpty()) {
377 log.error("type is empty");
378 result = Either.right(StorageOperationStatus.INVALID_ID);
382 Either<List<GroupTypeData>, StorageOperationStatus> groupTypeEither = janusGraphGenericDao
383 .getByCriteria(NodeTypeEnum.GroupType, properties, GroupTypeData.class)
385 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
386 if (groupTypeEither.isRight()) {
387 result = Either.right(groupTypeEither.right().value());
389 GroupTypeDataDefinition dataDefinition = groupTypeEither.left().value().stream()
390 .map(GroupTypeData::getGroupTypeDataDefinition)
393 result = getGroupTypeByUid(dataDefinition.getUniqueId());
399 janusGraphGenericDao.handleTransactionCommitRollback(inTransaction, result);
403 private Either<GroupTypeDefinition, StorageOperationStatus> buildGroupTypeDefinition(String uniqueId, GroupTypeData groupTypeNode) {
404 GroupTypeDefinition groupType = new GroupTypeDefinition(groupTypeNode.getGroupTypeDataDefinition());
405 return fillDerivedFrom(uniqueId, groupType)
407 .map(derivedFrom -> fillProperties(uniqueId, groupType, derivedFrom))
409 .bind(props -> fillCapabilities(uniqueId, groupType));
412 private Either<GroupTypeDefinition, StorageOperationStatus> fillCapabilities(String uniqueId, GroupTypeDefinition groupType) {
413 return getCapablities(uniqueId)
415 .map(capabilities -> {
416 groupType.setCapabilities(asCapabilitiesMap(capabilities));
421 private Either<GroupTypeData, StorageOperationStatus> fillDerivedFrom(String uniqueId, GroupTypeDefinition groupType) {
422 log.debug("#fillDerivedFrom - fetching group type {} derived node", groupType.getType());
423 return derivedFromOperation.getDerivedFromChild(uniqueId, NodeTypeEnum.GroupType, GroupTypeData.class)
425 .bind(this::handleDerivedFromNotExist)
427 .map(derivedFrom -> setDerivedFrom(groupType, derivedFrom));
431 private Either<List<PropertyDefinition>, StorageOperationStatus> fillProperties(String uniqueId, GroupTypeDefinition groupType, GroupTypeData derivedFromNode) {
432 log.debug("#fillProperties - fetching all properties for group type {}", groupType.getType());
433 return propertyOperation.findPropertiesOfNode(NodeTypeEnum.GroupType, uniqueId)
435 .bind(this::handleGroupTypeHasNoProperties)
437 .bind(propsMap -> fillDerivedFromProperties(groupType, derivedFromNode, new ArrayList<>(propsMap.values())));
440 Either<Map<String, PropertyDefinition>, StorageOperationStatus> handleGroupTypeHasNoProperties(JanusGraphOperationStatus err) {
441 if (err == JanusGraphOperationStatus.NOT_FOUND) {
442 return Either.left(new HashMap<>());
444 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(err));
447 private Either<List<PropertyDefinition>, StorageOperationStatus> fillDerivedFromProperties(GroupTypeDefinition groupType, GroupTypeData derivedFromNode, List<PropertyDefinition> groupTypeDirectProperties) {
448 if (derivedFromNode == null) {
449 groupType.setProperties(groupTypeDirectProperties);
450 return Either.left(groupTypeDirectProperties);
452 log.debug("#fillDerivedFromProperties - fetching all properties of derived from chain for group type {}", groupType.getType());
453 return propertyOperation.getAllPropertiesRec(derivedFromNode.getUniqueId(), NodeTypeEnum.GroupType, GroupTypeData.class)
455 .map(derivedFromProps -> {groupTypeDirectProperties.addAll(derivedFromProps); return groupTypeDirectProperties;})
457 .map(allProps -> {groupType.setProperties(allProps);return allProps;});
460 private Either<GroupTypeData, StorageOperationStatus> handleDerivedFromNotExist(StorageOperationStatus err) {
461 if (err == StorageOperationStatus.NOT_FOUND) {
462 return Either.left(null);
464 return Either.right(err);
467 private GroupTypeData setDerivedFrom(GroupTypeDefinition groupTypeDefinition, GroupTypeData derivedFrom) {
468 if (derivedFrom != null) {
469 groupTypeDefinition.setDerivedFrom(derivedFrom.getGroupTypeDataDefinition().getType());
476 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version) {
477 return getGroupTypeByTypeAndVersion(type, version, false);
481 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version, boolean inTransaction) {
482 Map<String, Object> mapCriteria = new HashMap<>();
483 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
484 mapCriteria.put(GraphPropertiesDictionary.VERSION.getProperty(), version);
486 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
490 * Add group type to graph.
492 * 1. Add group type node
494 * 2. Add edge between the former node to its parent(if exists)
496 * 3. Add property node and associate it to the node created at #1. (per property & if exists)
498 * @param groupTypeDefinition
501 private Either<GroupTypeData, JanusGraphOperationStatus> addGroupTypeToGraph(GroupTypeDefinition groupTypeDefinition) {
503 log.debug("Got group type {}", groupTypeDefinition);
505 String ctUniqueId = UniqueIdBuilder.buildGroupTypeUid(groupTypeDefinition.getType(), groupTypeDefinition.getVersion(), "grouptype");
507 GroupTypeData groupTypeData = buildGroupTypeData(groupTypeDefinition, ctUniqueId);
509 log.debug("Before adding group type to graph. groupTypeData = {}", groupTypeData);
511 Either<GroupTypeData, JanusGraphOperationStatus> createGTResult = janusGraphGenericDao
512 .createNode(groupTypeData, GroupTypeData.class);
513 log.debug("After adding group type to graph. status is = {}", createGTResult);
515 if (createGTResult.isRight()) {
516 JanusGraphOperationStatus operationStatus = createGTResult.right().value();
517 log.error("Failed to add group type {} to graph. status is {}", groupTypeDefinition.getType(), operationStatus);
518 return Either.right(operationStatus);
521 GroupTypeData resultCTD = createGTResult.left().value();
522 List<PropertyDefinition> properties = groupTypeDefinition.getProperties();
523 Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToCapablityType = propertyOperation.addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.GroupType, properties);
524 if (addPropertiesToCapablityType.isRight()) {
525 log.error("Failed add properties {} to capability {}", properties, groupTypeDefinition.getType());
526 return Either.right(addPropertiesToCapablityType.right().value());
529 String derivedFrom = groupTypeDefinition.getDerivedFrom();
530 if (derivedFrom != null) {
531 Either<GraphRelation, JanusGraphOperationStatus> createRelation = connectToDerivedFrom(ctUniqueId, derivedFrom);
532 if (createRelation.isRight()) {
533 return Either.right(createRelation.right().value());
537 Map<String, CapabilityDefinition> groupCapTypes = groupTypeDefinition.getCapabilities();
538 if (!MapUtils.isEmpty(groupCapTypes)) {
539 JanusGraphOperationStatus status = createCapabilities(groupTypeData, groupCapTypes);
540 if (status != JanusGraphOperationStatus.OK) {
541 return Either.right(status);
545 return Either.left(createGTResult.left().value());
550 private Either<GraphRelation, JanusGraphOperationStatus> connectToDerivedFrom(String ctUniqueId, String derivedFrom) {
551 log.debug("Before creating relation between Group Type with id {} to its parent {}", ctUniqueId, derivedFrom);
553 Either<GroupTypeData, JanusGraphOperationStatus> derivedFromGroupTypeResult =
555 .getNode(GraphPropertiesDictionary.TYPE.getProperty(), derivedFrom, GroupTypeData.class);
557 if (derivedFromGroupTypeResult.isLeft()) {
558 UniqueIdData from = new UniqueIdData(NodeTypeEnum.GroupType, ctUniqueId);
559 GroupTypeData to = derivedFromGroupTypeResult.left().value();
561 Either<GraphRelation, JanusGraphOperationStatus> createRelation = janusGraphGenericDao
562 .createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null);
563 log.debug("After create relation between Group Type with id {} to its parent {}, status is {}.", ctUniqueId, derivedFrom, createRelation);
564 return createRelation;
566 JanusGraphOperationStatus status = derivedFromGroupTypeResult.right().value();
567 log.debug("Failed to found parent Group Type {}, stauts is {}.", derivedFrom, status);
568 return Either.right(status);
572 private GroupTypeData buildGroupTypeData(GroupTypeDefinition groupTypeDefinition, String ctUniqueId) {
574 GroupTypeData groupTypeData = new GroupTypeData(groupTypeDefinition);
576 groupTypeData.getGroupTypeDataDefinition().setUniqueId(ctUniqueId);
577 Long creationDate = groupTypeData.getGroupTypeDataDefinition().getCreationTime();
578 if (creationDate == null) {
579 creationDate = System.currentTimeMillis();
581 groupTypeData.getGroupTypeDataDefinition().setCreationTime(creationDate);
582 groupTypeData.getGroupTypeDataDefinition().setModificationTime(creationDate);
584 return groupTypeData;
587 public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
588 Map<String, Object> propertiesToMatch = new HashMap<>();
589 propertiesToMatch.put(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childCandidateType);
590 Either<List<CapabilityTypeData>, JanusGraphOperationStatus> getResponse = janusGraphGenericDao
591 .getByCriteria(NodeTypeEnum.CapabilityType, propertiesToMatch, CapabilityTypeData.class);
592 if (getResponse.isRight()) {
593 JanusGraphOperationStatus janusGraphOperationStatus = getResponse.right().value();
594 log.debug("Couldn't fetch capability type {}, error: {}", childCandidateType,
595 janusGraphOperationStatus);
596 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(
597 janusGraphOperationStatus));
599 String childUniqueId = getResponse.left().value().get(0).getUniqueId();
600 Set<String> travelledTypes = new HashSet<>();
602 travelledTypes.add(childUniqueId);
603 Either<List<ImmutablePair<CapabilityTypeData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
604 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childUniqueId, GraphEdgeLabels.DERIVED_FROM,
605 NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
606 if (childrenNodes.isRight()) {
607 if (childrenNodes.right().value() != JanusGraphOperationStatus.NOT_FOUND) {
608 JanusGraphOperationStatus janusGraphOperationStatus = getResponse.right().value();
609 log.debug("Couldn't fetch derived from node for capability type {}, error: {}", childCandidateType,
610 janusGraphOperationStatus);
611 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(
612 janusGraphOperationStatus));
614 log.debug("Derived from node is not found for type {} - this is OK for root capability.", childCandidateType);
615 return Either.left(false);
618 String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
619 if (derivedFromUniqueId.equals(parentCandidateType)) {
620 log.debug("Verified that capability type {} derives from capability type {}", childCandidateType, parentCandidateType);
621 return Either.left(true);
623 childUniqueId = derivedFromUniqueId;
624 } while (!travelledTypes.contains(childUniqueId));
625 // this stop condition should never be used, if we use it, we have an
626 // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
627 // It's here just to avoid infinite loop in case we have such cycle.
628 log.error("Detected a cycle of \"derived from\" edges starting at capability type node {}", childUniqueId);
629 return Either.right(StorageOperationStatus.GENERAL_ERROR);
636 private Map<String, CapabilityDefinition> asCapabilitiesMap(List<CapabilityDefinition> list) {
638 .collect(Collectors.toMap(CapabilityDefinition::getName, Function.identity()));
642 private Either<GroupTypeDefinition, StorageOperationStatus> updateGroupTypeOnGraph(GroupTypeDefinition updatedGroupType, GroupTypeDefinition currGroupType) {
643 updateGroupTypeData(updatedGroupType, currGroupType);
644 return janusGraphGenericDao.updateNode(new GroupTypeData(updatedGroupType), GroupTypeData.class)
646 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus)
648 .bind(updatedNode -> updateGroupProperties(updatedGroupType.getUniqueId(), updatedGroupType.getProperties()))
650 .bind(updatedProperties -> updateGroupDerivedFrom(updatedGroupType, currGroupType.getDerivedFrom()))
652 .bind(result -> TypeOperations.mapOkStatus(result, null))
654 .bind(updatedDerivedFrom -> TypeOperations.mapOkStatus(mergeCapabilities(updatedGroupType), updatedGroupType))
656 .bind(def -> getGroupTypeByUid(def.getUniqueId()));
660 private Either<Map<String, PropertyData>, StorageOperationStatus> updateGroupProperties(String groupId, List<PropertyDefinition> properties) {
661 log.debug("#updateGroupProperties - updating group type properties for group type with id {}", groupId);
662 Map<String, PropertyDefinition> mapProperties = properties != null? properties.stream()
663 .collect(Collectors.toMap(PropertyDefinition::getName, Function.identity())): null;
664 return propertyOperation.mergePropertiesAssociatedToNode(NodeTypeEnum.GroupType, groupId, mapProperties)
666 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
671 private Either<GraphRelation, StorageOperationStatus> updateGroupDerivedFrom(GroupTypeDefinition updatedGroupType, String currDerivedFromGroupType) {
673 String groupTypeId = updatedGroupType.getUniqueId();
674 if (StringUtils.equals(updatedGroupType.getDerivedFrom(), currDerivedFromGroupType)) {
675 return Strings.isNullOrEmpty(currDerivedFromGroupType)?
676 Either.right(StorageOperationStatus.OK):
677 getLatestGroupTypeByType(currDerivedFromGroupType, true)
682 StorageOperationStatus status = isLegalToReplaceParent(currDerivedFromGroupType, updatedGroupType.getDerivedFrom(), updatedGroupType.getType());
683 if ( status != StorageOperationStatus.OK) {
684 return Either.right(status);
687 log.debug("#updateGroupDerivedFrom - updating group derived from relation for group type with id {}. old derived type {}. new derived type {}", groupTypeId, currDerivedFromGroupType, updatedGroupType.getDerivedFrom());
688 StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromGroupType(groupTypeId, currDerivedFromGroupType);
689 if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
690 return Either.right(deleteDerivedRelationStatus);
692 return addDerivedFromRelation(updatedGroupType, groupTypeId);
695 private StorageOperationStatus isLegalToReplaceParent(String oldTypeParent, String newTypeParent, String childType) {
696 return derivedFromOperation.isUpdateParentAllowed(oldTypeParent, newTypeParent, childType, NodeTypeEnum.GroupType, GroupTypeData.class, t -> t.getGroupTypeDataDefinition().getType());
699 private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(GroupTypeDataDefinition groupTypeDef, String gtUniqueId) {
700 String derivedFrom = groupTypeDef.getDerivedFrom();
701 if (derivedFrom == null) {
702 return Either.left(null);
704 log.debug("#addDerivedFromRelationBefore - adding derived from relation between group type {} to its parent {}", groupTypeDef.getType(), derivedFrom);
705 return this.getLatestGroupTypeByType(derivedFrom, true)
707 .bind(derivedFromGroup -> derivedFromOperation.addDerivedFromRelation(gtUniqueId, derivedFromGroup.getUniqueId(), NodeTypeEnum.GroupType));
710 private StorageOperationStatus deleteDerivedFromGroupType(String groupTypeId, String derivedFromType) {
711 if (derivedFromType == null) {
712 return StorageOperationStatus.OK;
714 log.debug("#deleteDerivedFromGroupType - deleting derivedFrom relation for group type with id {} and its derived type {}", groupTypeId, derivedFromType);
715 return getLatestGroupTypeByType(derivedFromType, true)
716 .either(derivedFromNode -> derivedFromOperation.removeDerivedFromRelation(groupTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.GroupType),
720 private void updateGroupTypeData(GroupTypeDefinition updatedTypeDefinition, GroupTypeDefinition currTypeDefinition) {
721 updatedTypeDefinition.setUniqueId(currTypeDefinition.getUniqueId());
722 updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime());
723 updatedTypeDefinition.setModificationTime(System.currentTimeMillis());