new unit tests for sdc-dao
[sdc.git] / catalog-model / src / main / java / org / openecomp / sdc / be / model / operations / impl / GroupTypeOperation.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.openecomp.sdc.be.model.operations.impl;
22
23 import static org.openecomp.sdc.be.dao.titan.TitanUtils.buildNotInPredicate;
24
25 import java.util.HashMap;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Optional;
30 import java.util.Set;
31 import java.util.stream.Collectors;
32
33 import javax.annotation.Resource;
34
35 import org.apache.commons.collections.CollectionUtils;
36 import org.apache.commons.lang3.tuple.ImmutablePair;
37 import org.apache.tinkerpop.gremlin.structure.Edge;
38 import org.openecomp.sdc.be.config.BeEcompErrorManager;
39 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
40 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
41 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
42 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
43 import org.openecomp.sdc.be.dao.titan.TitanGenericDao;
44 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
45 import org.openecomp.sdc.be.datatypes.elements.GroupTypeDataDefinition;
46 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
47 import org.openecomp.sdc.be.model.CapabilityTypeDefinition;
48 import org.openecomp.sdc.be.model.GroupTypeDefinition;
49 import org.openecomp.sdc.be.model.PropertyDefinition;
50 import org.openecomp.sdc.be.model.operations.StorageException;
51 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
52 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
53 import org.openecomp.sdc.be.resources.data.CapabilityTypeData;
54 import org.openecomp.sdc.be.resources.data.GroupTypeData;
55 import org.openecomp.sdc.be.resources.data.PropertyData;
56 import org.openecomp.sdc.be.resources.data.UniqueIdData;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.springframework.beans.factory.annotation.Qualifier;
60 import org.springframework.stereotype.Component;
61
62 import com.google.common.base.Strings;
63 import com.thinkaurelius.titan.graphdb.query.TitanPredicate;
64
65 import fj.data.Either;
66
67 @Component("group-type-operation")
68 public class GroupTypeOperation extends AbstractOperation implements IGroupTypeOperation {
69     @Resource
70     private CapabilityTypeOperation capabilityTypeOperation;
71
72     private static final Logger log = LoggerFactory.getLogger(GroupTypeOperation.class);
73
74     private static final String CREATE_FLOW_CONTEXT = "CreateGroupType";
75     private static final String GET_FLOW_CONTEXT = "GetGroupType";
76
77     private PropertyOperation propertyOperation;
78
79     private TitanGenericDao titanGenericDao;
80
81     public GroupTypeOperation(@Qualifier("titan-generic-dao") TitanGenericDao titanGenericDao, @Qualifier("property-operation") PropertyOperation propertyOperation) {
82         super();
83         this.propertyOperation = propertyOperation;
84         this.titanGenericDao = titanGenericDao;
85     }
86
87     /**
88      * FOR TEST ONLY
89      *
90      * @param titanGenericDao
91      */
92     public void setTitanGenericDao(TitanGenericDao titanGenericDao) {
93         this.titanGenericDao = titanGenericDao;
94     }
95
96     @Override
97     public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition) {
98
99         return addGroupType(groupTypeDefinition, false);
100     }
101
102     @Override
103     public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition, boolean inTransaction) {
104
105         Either<GroupTypeDefinition, StorageOperationStatus> result = null;
106
107         try {
108
109             Either<GroupTypeData, TitanOperationStatus> eitherStatus = addGroupTypeToGraph(groupTypeDefinition);
110
111             if (eitherStatus.isRight()) {
112                 BeEcompErrorManager.getInstance().logBeFailedCreateNodeError(CREATE_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
113                 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(eitherStatus.right().value()));
114
115             } else {
116                 GroupTypeData groupTypeData = eitherStatus.left().value();
117
118                 String uniqueId = groupTypeData.getUniqueId();
119                 Either<GroupTypeDefinition, StorageOperationStatus> groupTypeRes = this.getGroupType(uniqueId, true);
120
121                 if (groupTypeRes.isRight()) {
122                     BeEcompErrorManager.getInstance().logBeFailedRetrieveNodeError(GET_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
123                 } else {
124                     List<CapabilityTypeDefinition> groupCapTypes = groupTypeDefinition.getCapabilityTypes();
125                     if (!CollectionUtils.isEmpty(groupCapTypes)) {
126                         Optional<TitanOperationStatus> firstFailure = connectToCapabilityType(groupTypeData, groupCapTypes);
127                         if (firstFailure.isPresent()) {
128                             groupTypeRes = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(firstFailure.get()));
129                         }
130                     }
131                 }
132
133                 result = groupTypeRes;
134
135             }
136
137             return result;
138
139         } finally {
140             handleTransactionCommitRollback(inTransaction, result);
141         }
142
143     }
144
145
146     @Override
147     public Either<GroupTypeDefinition, StorageOperationStatus> upgradeGroupType(GroupTypeDefinition groupTypeDefinitionNew, GroupTypeDefinition groupTypeDefinitionOld) {
148         return upgradeGroupType(groupTypeDefinitionOld, groupTypeDefinitionNew, false);
149     }
150
151     @Override
152     public Either<GroupTypeDefinition, StorageOperationStatus> upgradeGroupType(GroupTypeDefinition groupTypeDefinitionNew, GroupTypeDefinition groupTypeDefinitionOld, boolean inTransaction) {
153         Either<GroupTypeDefinition, StorageOperationStatus> result = Either.left(groupTypeDefinitionNew);
154
155         try {
156             // dr2032:
157             // Right now upgrade Group is used only to ensure that already existing group type is connected by DERRIVED_FROM edge with it's parent
158             // We don't need to use for a while new node definition since following group type upgrade is not supported.
159             if (!Strings.isNullOrEmpty(groupTypeDefinitionOld.getDerivedFrom())) {
160                 result = ensureExsitanceDerivedFromEdge(groupTypeDefinitionOld);
161             }
162         } finally {
163             handleTransactionCommitRollback(inTransaction, result);
164         }
165
166         return result;
167     }
168
169     private Optional<TitanOperationStatus> connectToCapabilityType(GroupTypeData groupTypeData, List<CapabilityTypeDefinition> groupCapTypes) {
170         return groupCapTypes.stream()
171                 .map(groupCapTypeDef -> connectTo(groupTypeData, groupCapTypeDef))
172                 .filter(Either::isRight)
173                 .findFirst()
174                 .map(either -> either.right().value());
175     }
176
177     private Either<GraphRelation, TitanOperationStatus> connectTo(GroupTypeData groupTypeData, CapabilityTypeDefinition groupCapTypeDef) {
178         Either<CapabilityTypeData, TitanOperationStatus> eitherCapData = capabilityTypeOperation.getCapabilityTypeByType(groupCapTypeDef.getType());
179         if (eitherCapData.isLeft()) {
180             return titanGenericDao.createRelation(groupTypeData, eitherCapData.left().value(), GraphEdgeLabels.GROUP_TYPE_CAPABILITY_TYPE, null);
181         }
182
183         return Either.right(eitherCapData.right().value());
184     }
185
186     public List<GroupTypeDefinition> getAllGroupTypes(Set<String> excludedGroupTypes) {
187         Map<String, Map.Entry<TitanPredicate, Object>> predicateCriteria = buildNotInPredicate(GraphPropertiesDictionary.TYPE.getProperty(), excludedGroupTypes);
188         List<GroupTypeData> groupTypes = titanGenericDao.getByCriteriaWithPredicate(NodeTypeEnum.GroupType, predicateCriteria, GroupTypeData.class)
189                 .left()
190                 .on(this::onTitanAccessError);
191
192         return convertGroupTypesToDefinition(groupTypes);
193     }
194
195
196     private List<GroupTypeDefinition> convertGroupTypesToDefinition(List<GroupTypeData> groupTypes) {
197         return groupTypes.stream()
198                 .map(type -> new GroupTypeDefinition(type.getGroupTypeDataDefinition()))
199                 .collect(Collectors.toList());
200     }
201
202     private List<GroupTypeData> onTitanAccessError(TitanOperationStatus toe) {
203         throw new StorageException(
204                 DaoStatusConverter.convertTitanStatusToStorageStatus(toe));
205     }
206
207
208     public Either<GroupTypeDefinition, TitanOperationStatus> getGroupTypeByUid(String uniqueId) {
209
210         Either<GroupTypeDefinition, TitanOperationStatus> result = null;
211
212         Either<GroupTypeData, TitanOperationStatus> groupTypesRes = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), uniqueId, GroupTypeData.class);
213
214         if (groupTypesRes.isRight()) {
215             TitanOperationStatus status = groupTypesRes.right().value();
216             log.debug("Group type {} cannot be found in graph. status is {}", uniqueId, status);
217             return Either.right(status);
218         }
219
220         GroupTypeData gtData = groupTypesRes.left().value();
221         GroupTypeDefinition groupTypeDefinition = new GroupTypeDefinition(gtData.getGroupTypeDataDefinition());
222
223         TitanOperationStatus propertiesStatus = propertyOperation.fillProperties(uniqueId, NodeTypeEnum.GroupType, properList -> groupTypeDefinition.setProperties(properList));
224
225         if (propertiesStatus != TitanOperationStatus.OK) {
226             log.error("Failed to fetch properties of capability type {}", uniqueId);
227             return Either.right(propertiesStatus);
228         }
229
230         result = Either.left(groupTypeDefinition);
231
232         return result;
233     }
234
235     @Override
236     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId) {
237
238         return getGroupType(uniqueId, false);
239
240     }
241
242     @Override
243     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId, boolean inTransaction) {
244         return getElementType(this::getGroupTypeByUid, uniqueId, inTransaction);
245     }
246
247     @Override
248     public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type) {
249         return getLatestGroupTypeByType(type, false);
250     }
251
252     @Override
253     public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type, boolean inTransaction) {
254         Map<String, Object> mapCriteria = new HashMap<>();
255         mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
256         mapCriteria.put(GraphPropertiesDictionary.IS_HIGHEST_VERSION.getProperty(), true);
257
258         return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
259
260     }
261
262     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByCriteria(String type, Map<String, Object> properties, boolean inTransaction) {
263         Either<GroupTypeDefinition, StorageOperationStatus> result = null;
264         try {
265             if (type == null || type.isEmpty()) {
266                 log.error("type is empty");
267                 result = Either.right(StorageOperationStatus.INVALID_ID);
268                 return result;
269             }
270
271             Either<List<GroupTypeData>, TitanOperationStatus> groupTypeEither = titanGenericDao.getByCriteria(NodeTypeEnum.GroupType, properties, GroupTypeData.class);
272             if (groupTypeEither.isRight()) {
273                 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(groupTypeEither.right().value()));
274             } else {
275                 GroupTypeDataDefinition dataDefinition = groupTypeEither.left().value().stream().map(e -> e.getGroupTypeDataDefinition()).findFirst().get();
276                 result = getGroupType(dataDefinition.getUniqueId(), inTransaction);
277             }
278
279             return result;
280
281         } finally {
282             handleTransactionCommitRollback(inTransaction, result);
283         }
284     }
285
286     @Override
287     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version) {
288         return getGroupTypeByTypeAndVersion(type, version, false);
289     }
290
291     @Override
292     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version, boolean inTransaction) {
293         Map<String, Object> mapCriteria = new HashMap<>();
294         mapCriteria.put(GraphPropertiesDictionary.TYPE.getProperty(), type);
295         mapCriteria.put(GraphPropertiesDictionary.VERSION.getProperty(), version);
296
297         return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
298     }
299
300     /**
301      * Add group type to graph.
302      * <p>
303      * 1. Add group type node
304      * <p>
305      * 2. Add edge between the former node to its parent(if exists)
306      * <p>
307      * 3. Add property node and associate it to the node created at #1. (per property & if exists)
308      *
309      * @param groupTypeDefinition
310      * @return
311      */
312     private Either<GroupTypeData, TitanOperationStatus> addGroupTypeToGraph(GroupTypeDefinition groupTypeDefinition) {
313
314         log.debug("Got group type {}", groupTypeDefinition);
315
316         String ctUniqueId = UniqueIdBuilder.buildGroupTypeUid(groupTypeDefinition.getType(), groupTypeDefinition.getVersion());
317
318         GroupTypeData groupTypeData = buildGroupTypeData(groupTypeDefinition, ctUniqueId);
319
320         log.debug("Before adding group type to graph. groupTypeData = {}", groupTypeData);
321
322         Either<GroupTypeData, TitanOperationStatus> createGTResult = titanGenericDao.createNode(groupTypeData, GroupTypeData.class);
323         log.debug("After adding group type to graph. status is = {}", createGTResult);
324
325         if (createGTResult.isRight()) {
326             TitanOperationStatus operationStatus = createGTResult.right().value();
327             log.error("Failed to add group type {} to graph. status is {}", groupTypeDefinition.getType(), operationStatus);
328             return Either.right(operationStatus);
329         }
330
331         GroupTypeData resultCTD = createGTResult.left().value();
332         List<PropertyDefinition> properties = groupTypeDefinition.getProperties();
333         Either<Map<String, PropertyData>, TitanOperationStatus> addPropertiesToCapablityType = propertyOperation.addPropertiesToElementType(resultCTD.getUniqueId(), NodeTypeEnum.GroupType, properties);
334         if (addPropertiesToCapablityType.isRight()) {
335             log.error("Failed add properties {} to capability {}", properties, groupTypeDefinition.getType());
336             return Either.right(addPropertiesToCapablityType.right().value());
337         }
338
339         String derivedFrom = groupTypeDefinition.getDerivedFrom();
340         if (derivedFrom != null) {
341             Either<GraphRelation, TitanOperationStatus> createRelation = connectToDerivedFrom(ctUniqueId, derivedFrom);
342             if (createRelation.isRight()) {
343                 return Either.right(createRelation.right().value());
344             }
345         }
346
347         return Either.left(createGTResult.left().value());
348
349     }
350
351
352     private Either<GraphRelation, TitanOperationStatus> connectToDerivedFrom(String ctUniqueId, String derivedFrom) {
353         log.debug("Before creating relation between Group Type with id {} to its parent {}", ctUniqueId, derivedFrom);
354
355         Either<GroupTypeData, TitanOperationStatus> derivedFromGroupTypeResult =
356                 titanGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), derivedFrom, GroupTypeData.class);
357
358         if (derivedFromGroupTypeResult.isLeft()) {
359             UniqueIdData from = new UniqueIdData(NodeTypeEnum.GroupType, ctUniqueId);
360             GroupTypeData to = derivedFromGroupTypeResult.left().value();
361
362             Either<GraphRelation, TitanOperationStatus> createRelation = titanGenericDao.createRelation(from, to, GraphEdgeLabels.DERIVED_FROM, null);
363             log.debug("After create relation between Group Type with id {} to its parent {}, status is {}.", ctUniqueId, derivedFrom, createRelation);
364             return createRelation;
365         } else {
366             TitanOperationStatus status = derivedFromGroupTypeResult.right().value();
367             log.debug("Failed to found parent Group Type {}, stauts is {}.", derivedFrom, status);
368             return Either.right(status);
369         }
370     }
371
372
373     private Either<GroupTypeDefinition, StorageOperationStatus> ensureExsitanceDerivedFromEdge(GroupTypeDefinition groupTypeDefinition) {
374         Either<GroupTypeDefinition, StorageOperationStatus> result = Either.left(groupTypeDefinition);
375
376         GroupTypeData childGroupType = null;
377         GroupTypeData parentGroupType = null;
378
379         Either<GroupTypeData, TitanOperationStatus> childGroupTypeResult =
380                 titanGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), groupTypeDefinition.getType(), GroupTypeData.class);
381         if (childGroupTypeResult.isRight()) {
382             result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(childGroupTypeResult.right().value()));
383             log.debug("Filed to find GroupType with type {}, status is {}.", groupTypeDefinition.getType(), childGroupTypeResult);
384         } else {
385             childGroupType = childGroupTypeResult.left().value();
386         }
387
388
389         if (result.isLeft()) {
390             Either<GroupTypeData, TitanOperationStatus> parentGroupTypeResult =
391                     titanGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), groupTypeDefinition.getDerivedFrom(), GroupTypeData.class);
392             if (parentGroupTypeResult.isRight()) {
393                 result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(parentGroupTypeResult.right().value()));
394                 log.debug("Filed to find GroupType with type {}, status is {}.", groupTypeDefinition.getDerivedFrom(), parentGroupTypeResult);
395             } else {
396                 parentGroupType = parentGroupTypeResult.left().value();
397             }
398         }
399
400
401         if (childGroupType != null && parentGroupType != null) {
402             Either<Edge, TitanOperationStatus> edgeDerivedFromResult = titanGenericDao.getEdgeByNodes(childGroupType, parentGroupType, GraphEdgeLabels.DERIVED_FROM);
403             if (edgeDerivedFromResult.isLeft()) {
404                 log.debug("It was found relation {}. Don't need to create the edge.", edgeDerivedFromResult.left().value());
405             } else {
406                 Either<GraphRelation, TitanOperationStatus> createRelationResult = titanGenericDao.createRelation(childGroupType, parentGroupType, GraphEdgeLabels.DERIVED_FROM, null);
407                 log.debug("After create relation between Group Type with id {} to its parent with id {}, status is {}.",
408                         childGroupType.getKeyValueId().getValue(), parentGroupType.getKeyValueId().getValue(), createRelationResult);
409                 if (createRelationResult.isRight()) {
410                     result = Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(createRelationResult.right().value()));
411                 }
412             }
413
414         }
415
416
417         return result;
418     }
419
420
421     private GroupTypeData buildGroupTypeData(GroupTypeDefinition groupTypeDefinition, String ctUniqueId) {
422
423         GroupTypeData groupTypeData = new GroupTypeData(groupTypeDefinition);
424
425         groupTypeData.getGroupTypeDataDefinition().setUniqueId(ctUniqueId);
426         Long creationDate = groupTypeData.getGroupTypeDataDefinition().getCreationTime();
427         if (creationDate == null) {
428             creationDate = System.currentTimeMillis();
429         }
430         groupTypeData.getGroupTypeDataDefinition().setCreationTime(creationDate);
431         groupTypeData.getGroupTypeDataDefinition().setModificationTime(creationDate);
432
433         return groupTypeData;
434     }
435
436     public Either<Boolean, StorageOperationStatus> isCapabilityTypeDerivedFrom(String childCandidateType, String parentCandidateType) {
437         Map<String, Object> propertiesToMatch = new HashMap<String, Object>();
438         propertiesToMatch.put(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childCandidateType);
439         Either<List<CapabilityTypeData>, TitanOperationStatus> getResponse = titanGenericDao.getByCriteria(NodeTypeEnum.CapabilityType, propertiesToMatch, CapabilityTypeData.class);
440         if (getResponse.isRight()) {
441             TitanOperationStatus titanOperationStatus = getResponse.right().value();
442             log.debug("Couldn't fetch capability type {}, error: {}", childCandidateType, titanOperationStatus);
443             return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
444         }
445         String childUniqueId = getResponse.left().value().get(0).getUniqueId();
446         Set<String> travelledTypes = new HashSet<>();
447         do {
448             travelledTypes.add(childUniqueId);
449             Either<List<ImmutablePair<CapabilityTypeData, GraphEdge>>, TitanOperationStatus> childrenNodes = titanGenericDao.getChildrenNodes(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.CapabilityType), childUniqueId, GraphEdgeLabels.DERIVED_FROM,
450                     NodeTypeEnum.CapabilityType, CapabilityTypeData.class);
451             if (childrenNodes.isRight()) {
452                 if (childrenNodes.right().value() != TitanOperationStatus.NOT_FOUND) {
453                     TitanOperationStatus titanOperationStatus = getResponse.right().value();
454                     log.debug("Couldn't fetch derived from node for capability type {}, error: {}", childCandidateType, titanOperationStatus);
455                     return Either.right(DaoStatusConverter.convertTitanStatusToStorageStatus(titanOperationStatus));
456                 } else {
457                     log.debug("Derived from node is not found for type {} - this is OK for root capability.");
458                     return Either.left(false);
459                 }
460             }
461             String derivedFromUniqueId = childrenNodes.left().value().get(0).getLeft().getUniqueId();
462             if (derivedFromUniqueId.equals(parentCandidateType)) {
463                 log.debug("Verified that capability type {} derives from capability type {}", childCandidateType, parentCandidateType);
464                 return Either.left(true);
465             }
466             childUniqueId = derivedFromUniqueId;
467         } while (!travelledTypes.contains(childUniqueId));
468         // this stop condition should never be used, if we use it, we have an
469         // illegal cycle in graph - "derived from" hierarchy cannot be cycled.
470         // It's here just to avoid infinite loop in case we have such cycle.
471         log.error("Detected a cycle of \"derived from\" edges starting at capability type node {}", childUniqueId);
472         return Either.right(StorageOperationStatus.GENERAL_ERROR);
473     }
474
475     /**
476      * FOR TEST ONLY
477      *
478      * @param propertyOperation
479      */
480     public void setPropertyOperation(PropertyOperation propertyOperation) {
481         this.propertyOperation = propertyOperation;
482     }
483
484     @Override
485     public Either<GroupTypeData, TitanOperationStatus> getLatestGroupTypeByNameFromGraph(String name) {
486
487         return null;
488     }
489
490 }