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=========================================================
20 package org.openecomp.sdc.be.model.operations.impl;
22 import static org.openecomp.sdc.be.dao.janusgraph.JanusGraphUtils.buildNotInPredicate;
24 import com.google.common.base.Strings;
25 import fj.data.Either;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
33 import java.util.function.Function;
34 import java.util.stream.Collectors;
35 import org.apache.commons.collections.CollectionUtils;
36 import org.apache.commons.collections.MapUtils;
37 import org.apache.commons.lang.StringUtils;
38 import org.apache.commons.lang3.tuple.ImmutablePair;
39 import org.janusgraph.graphdb.query.JanusGraphPredicate;
40 import org.openecomp.sdc.be.config.BeEcompErrorManager;
41 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
42 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
43 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao;
44 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
45 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
46 import org.openecomp.sdc.be.dao.neo4j.GraphEdgePropertiesDictionary;
47 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
48 import org.openecomp.sdc.be.datatypes.elements.GroupTypeDataDefinition;
49 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
50 import org.openecomp.sdc.be.model.CapabilityDefinition;
51 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
52 import org.openecomp.sdc.be.model.GroupTypeDefinition;
53 import org.openecomp.sdc.be.model.PropertyDefinition;
54 import org.openecomp.sdc.be.model.operations.api.DerivedFromOperation;
55 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
56 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
57 import org.openecomp.sdc.be.model.operations.api.TypeOperations;
58 import org.openecomp.sdc.be.model.utils.TypeCompareUtils;
59 import org.openecomp.sdc.be.resources.data.CapabilityData;
60 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
61 import org.openecomp.sdc.be.resources.data.GroupTypeData;
62 import org.openecomp.sdc.be.resources.data.PropertyData;
63 import org.openecomp.sdc.be.resources.data.UniqueIdData;
64 import org.openecomp.sdc.common.log.wrappers.Logger;
65 import org.springframework.stereotype.Component;
67 @Component("group-type-operation")
68 public class GroupTypeOperation implements IGroupTypeOperation {
70 private static final Logger log = Logger.getLogger(GroupTypeOperation.class.getName());
71 private static final String CREATE_FLOW_CONTEXT = "CreateGroupType";
72 private final PropertyOperation propertyOperation;
73 private final JanusGraphGenericDao janusGraphGenericDao;
74 private final CapabilityTypeOperation capabilityTypeOperation;
75 private final CapabilityOperation capabilityOperation;
76 private final DerivedFromOperation derivedFromOperation;
77 private final OperationUtils operationUtils;
79 public GroupTypeOperation(JanusGraphGenericDao janusGraphGenericDao, PropertyOperation propertyOperation,
80 CapabilityTypeOperation capabilityTypeOperation, CapabilityOperation capabilityOperation,
81 DerivedFromOperation derivedFromOperation, OperationUtils operationUtils) {
82 this.janusGraphGenericDao = janusGraphGenericDao;
83 this.propertyOperation = propertyOperation;
84 this.capabilityTypeOperation = capabilityTypeOperation;
85 this.capabilityOperation = capabilityOperation;
86 this.derivedFromOperation = derivedFromOperation;
87 this.operationUtils = operationUtils;
90 public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition) {
91 Either<GroupTypeDefinition, StorageOperationStatus> validationRes = validateUpdateProperties(groupTypeDefinition);
92 if (validationRes.isRight()) {
93 log.error("#addGroupType - One or all properties of group type {} not valid. status is {}", groupTypeDefinition,
94 validationRes.right().value());
97 return addGroupType(groupTypeDefinition, true);
100 public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition, boolean inTransaction) {
101 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
103 Either<GroupTypeData, JanusGraphOperationStatus> eitherStatus = addGroupTypeToGraph(groupTypeDefinition);
104 if (eitherStatus.isRight()) {
105 BeEcompErrorManager.getInstance()
106 .logBeFailedCreateNodeError(CREATE_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
107 result = Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(eitherStatus.right().value()));
109 result = getGroupType(eitherStatus.left().value().getUniqueId(), inTransaction);
113 janusGraphGenericDao.handleTransactionCommitRollback(inTransaction, result);
117 public Either<GroupTypeDefinition, StorageOperationStatus> updateGroupType(GroupTypeDefinition updatedGroupType,
118 GroupTypeDefinition currGroupType) {
119 log.debug("updating group type {}", updatedGroupType.getType());
120 return updateGroupTypeOnGraph(updatedGroupType, currGroupType);
123 public Either<GroupTypeDefinition, StorageOperationStatus> validateUpdateProperties(GroupTypeDefinition groupTypeDefinition) {
124 JanusGraphOperationStatus error = null;
125 if (CollectionUtils.isNotEmpty(groupTypeDefinition.getProperties()) && !Strings.isNullOrEmpty(groupTypeDefinition.getDerivedFrom())) {
126 Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> allPropertiesRes = getAllGroupTypePropertiesFromAllDerivedFrom(
127 groupTypeDefinition.getDerivedFrom());
128 if (allPropertiesRes.isRight() && !allPropertiesRes.right().value().equals(JanusGraphOperationStatus.NOT_FOUND)) {
129 error = allPropertiesRes.right().value();
130 log.debug("Couldn't fetch derived from property nodes for group type {}, error: {}", groupTypeDefinition.getType(), error);
132 if (error == null && !allPropertiesRes.left().value().isEmpty()) {
133 Either<List<PropertyDefinition>, JanusGraphOperationStatus> validatePropertiesRes = propertyOperation
134 .validatePropertiesUniqueness(allPropertiesRes.left().value(), groupTypeDefinition.getProperties());
135 if (validatePropertiesRes.isRight()) {
136 error = validatePropertiesRes.right().value();
141 return Either.left(groupTypeDefinition);
143 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error));
146 private Either<Map<String, PropertyDefinition>, JanusGraphOperationStatus> getAllGroupTypePropertiesFromAllDerivedFrom(String firstParentType) {
147 return janusGraphGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), firstParentType, GroupTypeData.class).left().bind(
148 parentGroup -> propertyOperation
149 .getAllTypePropertiesFromAllDerivedFrom(parentGroup.getUniqueId(), NodeTypeEnum.GroupType, GroupTypeData.class));
152 private StorageOperationStatus mergeCapabilities(GroupTypeDefinition groupTypeDef) {
153 Map<String, CapabilityDefinition> updatedGroupTypeCapabilities = groupTypeDef.getCapabilities();
154 Map<String, CapabilityDefinition> newGroupTypeCapabilities;
155 Either<List<CapabilityDefinition>, StorageOperationStatus> oldCapabilitiesRes = getCapablities(groupTypeDef.getUniqueId());
156 if (oldCapabilitiesRes.isRight()) {
157 StorageOperationStatus status = oldCapabilitiesRes.right().value();
158 if (status == StorageOperationStatus.NOT_FOUND) {
159 newGroupTypeCapabilities = updatedGroupTypeCapabilities;
164 Map<String, CapabilityDefinition> oldCapabilities = asCapabilitiesMap(oldCapabilitiesRes.left().value());
165 newGroupTypeCapabilities = collectNewCapabilities(updatedGroupTypeCapabilities, oldCapabilities);
166 for (Map.Entry<String, CapabilityDefinition> oldEntry : oldCapabilities.entrySet()) {
167 String key = oldEntry.getKey();
168 CapabilityDefinition newCapDef = updatedGroupTypeCapabilities != null ? updatedGroupTypeCapabilities.get(key) : null;
169 CapabilityDefinition oldCapDef = oldEntry.getValue();
170 StorageOperationStatus deleteCapResult = deleteOutdatedCapability(newGroupTypeCapabilities, newCapDef, oldCapDef);
171 if (deleteCapResult != StorageOperationStatus.OK) {
172 return deleteCapResult;
176 JanusGraphOperationStatus createCapResult = createCapabilities(new GroupTypeData(groupTypeDef), newGroupTypeCapabilities);
177 return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(createCapResult);
181 * @param newGroupTypeCapabilities
186 private StorageOperationStatus deleteOutdatedCapability(Map<String, CapabilityDefinition> newGroupTypeCapabilities,
187 CapabilityDefinition newCapDef, CapabilityDefinition oldCapDef) {
188 if (!isUpdateAllowed(newCapDef, oldCapDef)) {
189 return StorageOperationStatus.MATCH_NOT_FOUND;
191 if (!TypeCompareUtils.capabilityEquals(oldCapDef, newCapDef)) {
192 StorageOperationStatus deleteCapResult = capabilityOperation.deleteCapability(oldCapDef);
193 if (deleteCapResult == StorageOperationStatus.OK) {
194 newGroupTypeCapabilities.put(newCapDef.getName(), newCapDef);
196 return deleteCapResult;
199 return StorageOperationStatus.OK;
202 private boolean isUpdateAllowed(CapabilityDefinition newCapDef, CapabilityDefinition oldCapDef) {
203 if (newCapDef == null) {
204 log.error("#upsertCapabilities - Failed due to attempt to delete the capability with id {}", oldCapDef.getUniqueId());
207 if (newCapDef.getType() == null || !newCapDef.getType().equals(oldCapDef.getType())) {
208 log.error("#upsertCapabilities - Failed due to attempt to change type of the capability with id {}", oldCapDef.getUniqueId());
215 * @param updatedGroupTypeCapabilities
216 * @param oldCapabilities
219 private Map<String, CapabilityDefinition> collectNewCapabilities(Map<String, CapabilityDefinition> updatedGroupTypeCapabilities,
220 Map<String, CapabilityDefinition> oldCapabilities) {
221 return updatedGroupTypeCapabilities != null ? updatedGroupTypeCapabilities.entrySet().stream()
222 .filter(entry -> !oldCapabilities.containsKey(entry.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
226 private JanusGraphOperationStatus createCapabilities(GroupTypeData groupTypeData, Map<String, CapabilityDefinition> groupCapabilities) {
227 if (MapUtils.isEmpty(groupCapabilities)) {
228 return JanusGraphOperationStatus.OK;
230 return groupCapabilities.values().stream().map(v -> createCapability(groupTypeData, v)).filter(Either::isRight).findFirst()
231 .map(either -> either.right().value()).orElse(JanusGraphOperationStatus.OK);
234 private Either<GraphRelation, JanusGraphOperationStatus> createCapability(GroupTypeData groupTypeData, CapabilityDefinition capabilityDef) {
235 Either<CapabilityTypeDefinition, JanusGraphOperationStatus> eitherCapData = capabilityTypeOperation
236 .getCapabilityTypeByType(capabilityDef.getType());
237 return eitherCapData.left().map(CapabilityTypeData::new).left()
238 .bind(capTypeData -> capabilityOperation.addCapabilityToGraph(groupTypeData.getUniqueId(), capTypeData, capabilityDef)).left()
239 .bind(capData -> connectToCapability(groupTypeData, capData, capabilityDef.getName()));
243 * Get capability with all relevant properties
248 private Either<List<CapabilityDefinition>, StorageOperationStatus> getCapablities(String groupTypeId) {
249 Either<List<ImmutablePair<CapabilityData, GraphEdge>>, JanusGraphOperationStatus> groupCapabilitiesOnGraph = janusGraphGenericDao
250 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), groupTypeId, GraphEdgeLabels.GROUP_TYPE_CAPABILITY,
251 NodeTypeEnum.Capability, CapabilityData.class, true);
252 if (groupCapabilitiesOnGraph.isRight()) {
253 JanusGraphOperationStatus capabilityStatus = groupCapabilitiesOnGraph.right().value();
254 if (capabilityStatus == JanusGraphOperationStatus.NOT_FOUND) {
255 return Either.left(Collections.emptyList());
257 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(capabilityStatus));
259 List<ImmutablePair<CapabilityData, GraphEdge>> groupCapabilites = groupCapabilitiesOnGraph.left().value();
260 groupCapabilites.forEach(this::fillCapabilityName);
261 return capabilityOperation.getCapabilitiesWithProps(groupCapabilites).right().map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
264 private void fillCapabilityName(ImmutablePair<CapabilityData, GraphEdge> pair) {
265 pair.getLeft().getCapabilityDataDefinition()
266 .setName((String) pair.getRight().getProperties().get(GraphEdgePropertiesDictionary.NAME.getProperty()));
269 private Either<GraphRelation, JanusGraphOperationStatus> connectToCapability(GroupTypeData groupTypeData, CapabilityData capabilityData,
270 String capabilityName) {
271 Map<String, Object> properties = new HashMap<>();
272 properties.put(GraphEdgePropertiesDictionary.NAME.getProperty(), capabilityName);
273 return janusGraphGenericDao.createRelation(groupTypeData, capabilityData, GraphEdgeLabels.GROUP_TYPE_CAPABILITY, properties);
276 public List<GroupTypeDefinition> getAllGroupTypes(Set<String> excludedGroupTypes) {
277 Map<String, Map.Entry<JanusGraphPredicate, Object>> predicateCriteria = buildNotInPredicate(GraphPropertiesDictionary.TYPE.getProperty(),
279 List<GroupTypeData> groupTypes = janusGraphGenericDao
280 .getByCriteriaWithPredicate(NodeTypeEnum.GroupType, predicateCriteria, GroupTypeData.class).left()
281 .on(operationUtils::onJanusGraphOperationFailure);
282 return convertGroupTypesToDefinition(groupTypes);
285 private List<GroupTypeDefinition> convertGroupTypesToDefinition(List<GroupTypeData> groupTypes) {
286 return groupTypes.stream().map(type -> new GroupTypeDefinition(type.getGroupTypeDataDefinition())).collect(Collectors.toList());
289 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByUid(String uniqueId) {
290 log.debug("#getGroupTypeByUid - fetching group type with id {}", uniqueId);
291 return janusGraphGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), uniqueId, GroupTypeData.class).right()
292 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left().bind(groupType -> buildGroupTypeDefinition(uniqueId, groupType));
295 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId, boolean inTransaction) {
296 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
298 Either<GroupTypeDefinition, StorageOperationStatus> ctResult = getGroupTypeByUid(uniqueId);
299 if (ctResult.isRight()) {
300 StorageOperationStatus status = ctResult.right().value();
301 if (status != StorageOperationStatus.NOT_FOUND) {
302 log.error("Failed to retrieve information on element uniqueId: {}. status is {}", uniqueId, status);
304 result = Either.right(ctResult.right().value());
307 result = Either.left(ctResult.left().value());
310 janusGraphGenericDao.handleTransactionCommitRollback(inTransaction, result);
314 public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type) {
315 return getLatestGroupTypeByType(type, true);
318 public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type, boolean inTransaction) {
319 Map<String, Object> mapCriteria = new HashMap<>();
320 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
321 mapCriteria.put(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty(), true);
322 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
325 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByCriteria(String type, Map<String, Object> properties,
326 boolean inTransaction) {
327 Either<GroupTypeDefinition, StorageOperationStatus> result = null;
329 if (type == null || type.isEmpty()) {
330 log.error("type is empty");
331 result = Either.right(StorageOperationStatus.INVALID_ID);
334 Either<List<GroupTypeData>, StorageOperationStatus> groupTypeEither = janusGraphGenericDao
335 .getByCriteria(NodeTypeEnum.GroupType, properties, GroupTypeData.class).right()
336 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
337 if (groupTypeEither.isRight()) {
338 result = Either.right(groupTypeEither.right().value());
340 GroupTypeDataDefinition dataDefinition = groupTypeEither.left().value().stream().map(GroupTypeData::getGroupTypeDataDefinition)
342 result = getGroupTypeByUid(dataDefinition.getUniqueId());
346 janusGraphGenericDao.handleTransactionCommitRollback(inTransaction, result);
350 private Either<GroupTypeDefinition, StorageOperationStatus> buildGroupTypeDefinition(String uniqueId, GroupTypeData groupTypeNode) {
351 GroupTypeDefinition groupType = new GroupTypeDefinition(groupTypeNode.getGroupTypeDataDefinition());
352 return fillDerivedFrom(uniqueId, groupType).left().map(derivedFrom -> fillProperties(uniqueId, groupType, derivedFrom)).left()
353 .bind(props -> fillCapabilities(uniqueId, groupType));
356 private Either<GroupTypeDefinition, StorageOperationStatus> fillCapabilities(String uniqueId, GroupTypeDefinition groupType) {
357 return getCapablities(uniqueId).left().map(capabilities -> {
358 groupType.setCapabilities(asCapabilitiesMap(capabilities));
363 private Either<GroupTypeData, StorageOperationStatus> fillDerivedFrom(String uniqueId, GroupTypeDefinition groupType) {
364 log.debug("#fillDerivedFrom - fetching group type {} derived node", groupType.getType());
365 return derivedFromOperation.getDerivedFromChild(uniqueId, NodeTypeEnum.GroupType, GroupTypeData.class).right()
366 .bind(this::handleDerivedFromNotExist).left().map(derivedFrom -> setDerivedFrom(groupType, derivedFrom));
369 private Either<List<PropertyDefinition>, StorageOperationStatus> fillProperties(String uniqueId, GroupTypeDefinition groupType,
370 GroupTypeData derivedFromNode) {
371 log.debug("#fillProperties - fetching all properties for group type {}", groupType.getType());
372 return propertyOperation.findPropertiesOfNode(NodeTypeEnum.GroupType, uniqueId).right().bind(this::handleGroupTypeHasNoProperties).left()
373 .bind(propsMap -> fillDerivedFromProperties(groupType, derivedFromNode, new ArrayList<>(propsMap.values())));
376 Either<Map<String, PropertyDefinition>, StorageOperationStatus> handleGroupTypeHasNoProperties(JanusGraphOperationStatus err) {
377 if (err == JanusGraphOperationStatus.NOT_FOUND) {
378 return Either.left(new HashMap<>());
380 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(err));
383 private Either<List<PropertyDefinition>, StorageOperationStatus> fillDerivedFromProperties(GroupTypeDefinition groupType,
384 GroupTypeData derivedFromNode,
385 List<PropertyDefinition> groupTypeDirectProperties) {
386 if (derivedFromNode == null) {
387 groupType.setProperties(groupTypeDirectProperties);
388 return Either.left(groupTypeDirectProperties);
390 log.debug("#fillDerivedFromProperties - fetching all properties of derived from chain for group type {}", groupType.getType());
391 return propertyOperation.getAllPropertiesRec(derivedFromNode.getUniqueId(), NodeTypeEnum.GroupType, GroupTypeData.class).left()
392 .map(derivedFromProps -> {
393 groupTypeDirectProperties.addAll(derivedFromProps);
394 return groupTypeDirectProperties;
395 }).left().map(allProps -> {
396 groupType.setProperties(allProps);
401 private Either<GroupTypeData, StorageOperationStatus> handleDerivedFromNotExist(StorageOperationStatus err) {
402 if (err == StorageOperationStatus.NOT_FOUND) {
403 return Either.left(null);
405 return Either.right(err);
408 private GroupTypeData setDerivedFrom(GroupTypeDefinition groupTypeDefinition, GroupTypeData derivedFrom) {
409 if (derivedFrom != null) {
410 groupTypeDefinition.setDerivedFrom(derivedFrom.getGroupTypeDataDefinition().getType());
415 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version) {
416 return getGroupTypeByTypeAndVersion(type, version, false);
419 public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version, boolean inTransaction) {
420 Map<String, Object> mapCriteria = new HashMap<>();
421 mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
422 mapCriteria.put(GraphPropertiesDictionary.VERSION.getProperty(), version);
423 return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
427 * Add group type to graph.
429 * 1. Add group type node
431 * 2. Add edge between the former node to its parent(if exists)
433 * 3. Add property node and associate it to the node created at #1. (per property & if exists)
435 * @param groupTypeDefinition
438 private Either<GroupTypeData, JanusGraphOperationStatus> addGroupTypeToGraph(GroupTypeDefinition groupTypeDefinition) {
439 log.debug("Got group type {}", groupTypeDefinition);
440 String ctUniqueId = UniqueIdBuilder.buildGroupTypeUid(groupTypeDefinition.getType(), groupTypeDefinition.getVersion(), "grouptype");
441 GroupTypeData groupTypeData = buildGroupTypeData(groupTypeDefinition, ctUniqueId);
442 log.debug("Before adding group type to graph. groupTypeData = {}", groupTypeData);
443 Either<GroupTypeData, JanusGraphOperationStatus> createGTResult = janusGraphGenericDao.createNode(groupTypeData, GroupTypeData.class);
444 log.debug("After adding group type to graph. status is = {}", createGTResult);
445 if (createGTResult.isRight()) {
446 JanusGraphOperationStatus operationStatus = createGTResult.right().value();
447 log.error("Failed to add group type {} to graph. status is {}", groupTypeDefinition.getType(), operationStatus);
448 return Either.right(operationStatus);
450 GroupTypeData resultCTD = createGTResult.left().value();
451 List<PropertyDefinition> properties = groupTypeDefinition.getProperties();
452 Either<Map<String, PropertyData>, JanusGraphOperationStatus> addPropertiesToCapablityType = propertyOperation
453 .addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.GroupType, properties);
454 if (addPropertiesToCapablityType.isRight()) {
455 log.error("Failed add properties {} to capability {}", properties, groupTypeDefinition.getType());
456 return Either.right(addPropertiesToCapablityType.right().value());
458 String derivedFrom = groupTypeDefinition.getDerivedFrom();
459 if (derivedFrom != null) {
460 Either<GraphRelation, JanusGraphOperationStatus> createRelation = connectToDerivedFrom(ctUniqueId, derivedFrom);
461 if (createRelation.isRight()) {
462 return Either.right(createRelation.right().value());
465 Map<String, CapabilityDefinition> groupCapTypes = groupTypeDefinition.getCapabilities();
466 if (!MapUtils.isEmpty(groupCapTypes)) {
467 JanusGraphOperationStatus status = createCapabilities(groupTypeData, groupCapTypes);
468 if (status != JanusGraphOperationStatus.OK) {
469 return Either.right(status);
472 return Either.left(createGTResult.left().value());
475 private Either<GraphRelation, JanusGraphOperationStatus> connectToDerivedFrom(String ctUniqueId, String derivedFrom) {
476 log.debug("Before creating relation between Group Type with id {} to its parent {}", ctUniqueId, derivedFrom);
477 Either<GroupTypeData, JanusGraphOperationStatus> derivedFromGroupTypeResult = janusGraphGenericDao
478 .getNode(GraphPropertiesDictionary.TYPE.getProperty(), derivedFrom, GroupTypeData.class);
479 if (derivedFromGroupTypeResult.isLeft()) {
480 UniqueIdData from = new UniqueIdData(NodeTypeEnum.GroupType, ctUniqueId);
481 GroupTypeData to = derivedFromGroupTypeResult.left().value();
482 Either<GraphRelation, JanusGraphOperationStatus> createRelation = janusGraphGenericDao
483 .createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null);
484 log.debug("After create relation between Group Type with id {} to its parent {}, status is {}.", ctUniqueId, derivedFrom, createRelation);
485 return createRelation;
487 JanusGraphOperationStatus status = derivedFromGroupTypeResult.right().value();
488 log.debug("Failed to found parent Group Type {}, stauts is {}.", derivedFrom, status);
489 return Either.right(status);
493 private GroupTypeData buildGroupTypeData(GroupTypeDefinition groupTypeDefinition, String ctUniqueId) {
494 GroupTypeData groupTypeData = new GroupTypeData(groupTypeDefinition);
495 groupTypeData.getGroupTypeDataDefinition().setUniqueId(ctUniqueId);
496 Long creationDate = groupTypeData.getGroupTypeDataDefinition().getCreationTime();
497 if (creationDate == null) {
498 creationDate = System.currentTimeMillis();
500 groupTypeData.getGroupTypeDataDefinition().setCreationTime(creationDate);
501 groupTypeData.getGroupTypeDataDefinition().setModificationTime(creationDate);
502 return groupTypeData;
505 public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
506 Map<String, Object> propertiesToMatch = new HashMap<>();
507 propertiesToMatch.put(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childCandidateType);
508 Either<List<CapabilityTypeData>, JanusGraphOperationStatus> getResponse = janusGraphGenericDao
509 .getByCriteria(NodeTypeEnum.CapabilityType, propertiesToMatch, CapabilityTypeData.class);
510 if (getResponse.isRight()) {
511 JanusGraphOperationStatus janusGraphOperationStatus = getResponse.right().value();
512 log.debug("Couldn't fetch capability type {}, error: {}", childCandidateType, janusGraphOperationStatus);
513 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphOperationStatus));
515 String childUniqueId = getResponse.left().value().get(0).getUniqueId();
516 Set<String> travelledTypes = new HashSet<>();
518 travelledTypes.add(childUniqueId);
519 Either<List<ImmutablePair<CapabilityTypeData, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = janusGraphGenericDao
520 .getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childUniqueId, GraphEdgeLabels.DERIVED_FROM,
521 NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
522 if (childrenNodes.isRight()) {
523 if (childrenNodes.right().value() != JanusGraphOperationStatus.NOT_FOUND) {
524 JanusGraphOperationStatus janusGraphOperationStatus = getResponse.right().value();
525 log.debug("Couldn't fetch derived from node for capability type {}, error: {}", childCandidateType, janusGraphOperationStatus);
526 return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(janusGraphOperationStatus));
528 log.debug("Derived from node is not found for type {} - this is OK for root capability.", childCandidateType);
529 return Either.left(false);
532 String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
533 if (derivedFromUniqueId.equals(parentCandidateType)) {
534 log.debug("Verified that capability type {} derives from capability type {}", childCandidateType, parentCandidateType);
535 return Either.left(true);
537 childUniqueId = derivedFromUniqueId;
538 } while (!travelledTypes.contains(childUniqueId));
539 // this stop condition should never be used, if we use it, we have an
541 // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
543 // It's here just to avoid infinite loop in case we have such cycle.
544 log.error("Detected a cycle of \"derived from\" edges starting at capability type node {}", childUniqueId);
545 return Either.right(StorageOperationStatus.GENERAL_ERROR);
552 private Map<String, CapabilityDefinition> asCapabilitiesMap(List<CapabilityDefinition> list) {
553 return list.stream().collect(Collectors.toMap(CapabilityDefinition::getName, Function.identity()));
556 private Either<GroupTypeDefinition, StorageOperationStatus> updateGroupTypeOnGraph(GroupTypeDefinition updatedGroupType,
557 GroupTypeDefinition currGroupType) {
558 updateGroupTypeData(updatedGroupType, currGroupType);
559 return janusGraphGenericDao.updateNode(new GroupTypeData(updatedGroupType), GroupTypeData.class).right()
560 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus).left()
561 .bind(updatedNode -> updateGroupProperties(updatedGroupType.getUniqueId(), updatedGroupType.getProperties())).left()
562 .bind(updatedProperties -> updateGroupDerivedFrom(updatedGroupType, currGroupType.getDerivedFrom())).right()
563 .bind(result -> TypeOperations.mapOkStatus(result, null)).left()
564 .bind(updatedDerivedFrom -> TypeOperations.mapOkStatus(mergeCapabilities(updatedGroupType), updatedGroupType)).left()
565 .bind(def -> getGroupTypeByUid(def.getUniqueId()));
568 private Either<Map<String, PropertyData>, StorageOperationStatus> updateGroupProperties(String groupId, List<PropertyDefinition> properties) {
569 log.debug("#updateGroupProperties - updating group type properties for group type with id {}", groupId);
570 Map<String, PropertyDefinition> mapProperties =
571 properties != null ? properties.stream().collect(Collectors.toMap(PropertyDefinition::getName, Function.identity())) : null;
572 return propertyOperation.mergePropertiesAssociatedToNode(NodeTypeEnum.GroupType, groupId, mapProperties).right()
573 .map(DaoStatusConverter::convertJanusGraphStatusToStorageStatus);
576 private Either<GraphRelation, StorageOperationStatus> updateGroupDerivedFrom(GroupTypeDefinition updatedGroupType,
577 String currDerivedFromGroupType) {
578 String groupTypeId = updatedGroupType.getUniqueId();
579 if (StringUtils.equals(updatedGroupType.getDerivedFrom(), currDerivedFromGroupType)) {
580 return Strings.isNullOrEmpty(currDerivedFromGroupType) ? Either.right(StorageOperationStatus.OK)
581 : getLatestGroupTypeByType(currDerivedFromGroupType, true).left().map(def -> null);
583 StorageOperationStatus status = isLegalToReplaceParent(currDerivedFromGroupType, updatedGroupType.getDerivedFrom(),
584 updatedGroupType.getType());
585 if (status != StorageOperationStatus.OK) {
586 return Either.right(status);
589 "#updateGroupDerivedFrom - updating group derived from relation for group type with id {}. old derived type {}. new derived type {}",
590 groupTypeId, currDerivedFromGroupType, updatedGroupType.getDerivedFrom());
591 StorageOperationStatus deleteDerivedRelationStatus = deleteDerivedFromGroupType(groupTypeId, currDerivedFromGroupType);
592 if (deleteDerivedRelationStatus != StorageOperationStatus.OK) {
593 return Either.right(deleteDerivedRelationStatus);
595 return addDerivedFromRelation(updatedGroupType, groupTypeId);
598 private StorageOperationStatus isLegalToReplaceParent(String oldTypeParent, String newTypeParent, String childType) {
599 return derivedFromOperation.isUpdateParentAllowed(oldTypeParent, newTypeParent, childType, NodeTypeEnum.GroupType, GroupTypeData.class,
600 t -> t.getGroupTypeDataDefinition().getType());
603 private Either<GraphRelation, StorageOperationStatus> addDerivedFromRelation(GroupTypeDataDefinition groupTypeDef, String gtUniqueId) {
604 String derivedFrom = groupTypeDef.getDerivedFrom();
605 if (derivedFrom == null) {
606 return Either.left(null);
608 log.debug("#addDerivedFromRelationBefore - adding derived from relation between group type {} to its parent {}", groupTypeDef.getType(),
610 return this.getLatestGroupTypeByType(derivedFrom, true).left().bind(
611 derivedFromGroup -> derivedFromOperation.addDerivedFromRelation(gtUniqueId, derivedFromGroup.getUniqueId(), NodeTypeEnum.GroupType));
614 private StorageOperationStatus deleteDerivedFromGroupType(String groupTypeId, String derivedFromType) {
615 if (derivedFromType == null) {
616 return StorageOperationStatus.OK;
618 log.debug("#deleteDerivedFromGroupType - deleting derivedFrom relation for group type with id {} and its derived type {}", groupTypeId,
620 return getLatestGroupTypeByType(derivedFromType, true).either(
621 derivedFromNode -> derivedFromOperation.removeDerivedFromRelation(groupTypeId, derivedFromNode.getUniqueId(), NodeTypeEnum.GroupType),
625 private void updateGroupTypeData(GroupTypeDefinition updatedTypeDefinition, GroupTypeDefinition currTypeDefinition) {
626 updatedTypeDefinition.setUniqueId(currTypeDefinition.getUniqueId());
627 updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime());
628 updatedTypeDefinition.setModificationTime(System.currentTimeMillis());