Sync Integ to Master
[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 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;
52
53 import javax.annotation.Resource;
54 import java.util.HashMap;
55 import java.util.HashSet;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Optional;
59 import java.util.Set;
60 import java.util.stream.Collectors;
61
62 import static org.openecomp.sdc.be.dao.titan.TitanUtils.buildNotInPredicate;
63
64 @Component("group-type-operation")
65 public class GroupTypeOperation extends AbstractOperation implements IGroupTypeOperation {
66     @Resource
67     private CapabilityTypeOperation capabilityTypeOperation;
68
69     private static final Logger log = LoggerFactory.getLogger(GroupTypeOperation.class);
70
71     private static final String CREATE_FLOW_CONTEXT = "CreateGroupType";
72     private static final String GET_FLOW_CONTEXT = "GetGroupType";
73
74     private PropertyOperation propertyOperation;
75
76     private TitanGenericDao titanGenericDao;
77
78     public GroupTypeOperation(@Qualifier("titan-generic-dao") TitanGenericDao titanGenericDao, @Qualifier("property-operation") PropertyOperation propertyOperation) {
79         super();
80         this.propertyOperation = propertyOperation;
81         this.titanGenericDao = titanGenericDao;
82     }
83
84     /**
85      * FOR TEST ONLY
86      *
87      * @param titanGenericDao
88      */
89     public void setTitanGenericDao(TitanGenericDao titanGenericDao) {
90         this.titanGenericDao = titanGenericDao;
91     }
92
93     @Override
94     public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition) {
95
96         return addGroupType(groupTypeDefinition, false);
97     }
98
99     @Override
100     public Either<GroupTypeDefinition, StorageOperationStatus> addGroupType(GroupTypeDefinition groupTypeDefinition, boolean inTransaction) {
101
102         Either<GroupTypeDefinition, StorageOperationStatus> result = null;
103
104         try {
105
106             Either<GroupTypeData, TitanOperationStatus> eitherStatus = addGroupTypeToGraph(groupTypeDefinition);
107
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()));
111
112             } else {
113                 GroupTypeData groupTypeData = eitherStatus.left().value();
114
115                 String uniqueId = groupTypeData.getUniqueId();
116                 Either<GroupTypeDefinition, StorageOperationStatus> groupTypeRes = this.getGroupType(uniqueId, true);
117
118                 if (groupTypeRes.isRight()) {
119                     BeEcompErrorManager.getInstance().logBeFailedRetrieveNodeError(GET_FLOW_CONTEXT, groupTypeDefinition.getType(), eitherStatus.right().value().name());
120                 } else {
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()));
126                         }
127                     }
128                 }
129
130                 result = groupTypeRes;
131
132             }
133
134             return result;
135
136         } finally {
137             handleTransactionCommitRollback(inTransaction, result);
138         }
139
140     }
141
142
143     @Override
144     public Either<GroupTypeDefinition, StorageOperationStatus> upgradeGroupType(GroupTypeDefinition groupTypeDefinitionNew, GroupTypeDefinition groupTypeDefinitionOld) {
145         return upgradeGroupType(groupTypeDefinitionOld, groupTypeDefinitionNew, false);
146     }
147
148     @Override
149     public Either<GroupTypeDefinition, StorageOperationStatus> upgradeGroupType(GroupTypeDefinition groupTypeDefinitionNew, GroupTypeDefinition groupTypeDefinitionOld, boolean inTransaction) {
150         Either<GroupTypeDefinition, StorageOperationStatus> result = Either.left(groupTypeDefinitionNew);
151
152         try {
153             // dr2032:
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);
158             }
159         } finally {
160             handleTransactionCommitRollback(inTransaction, result);
161         }
162
163         return result;
164     }
165
166     private Optional<TitanOperationStatus> connectToCapabilityType(GroupTypeData groupTypeData, List<CapabilityTypeDefinition> groupCapTypes) {
167         return groupCapTypes.stream()
168                 .map(groupCapTypeDef -> connectTo(groupTypeData, groupCapTypeDef))
169                 .filter(Either::isRight)
170                 .findFirst()
171                 .map(either -> either.right().value());
172     }
173
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);
178         }
179
180         return Either.right(eitherCapData.right().value());
181     }
182
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)
186                 .left()
187                 .on(this::onTitanAccessError);
188
189         return convertGroupTypesToDefinition(groupTypes);
190     }
191
192
193     private List<GroupTypeDefinition> convertGroupTypesToDefinition(List<GroupTypeData> groupTypes) {
194         return groupTypes.stream()
195                 .map(type -> new GroupTypeDefinition(type.getGroupTypeDataDefinition()))
196                 .collect(Collectors.toList());
197     }
198
199     private List<GroupTypeData> onTitanAccessError(TitanOperationStatus toe) {
200         throw new StorageException(
201                 DaoStatusConverter.convertTitanStatusToStorageStatus(toe));
202     }
203
204
205     public Either<GroupTypeDefinition, TitanOperationStatus> getGroupTypeByUid(String uniqueId) {
206
207         Either<GroupTypeDefinition, TitanOperationStatus> result = null;
208
209         Either<GroupTypeData, TitanOperationStatus> groupTypesRes = titanGenericDao.getNode(UniqueIdBuilder.getKeyByNodeType(NodeTypeEnum.GroupType), uniqueId, GroupTypeData.class);
210
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);
215         }
216
217         GroupTypeData gtData = groupTypesRes.left().value();
218         GroupTypeDefinition groupTypeDefinition = new GroupTypeDefinition(gtData.getGroupTypeDataDefinition());
219
220         TitanOperationStatus propertiesStatus = propertyOperation.fillProperties(uniqueId, NodeTypeEnum.GroupType, properList -> groupTypeDefinition.setProperties(properList));
221
222         if (propertiesStatus != TitanOperationStatus.OK) {
223             log.error("Failed to fetch properties of capability type {}", uniqueId);
224             return Either.right(propertiesStatus);
225         }
226
227         result = Either.left(groupTypeDefinition);
228
229         return result;
230     }
231
232     @Override
233     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId) {
234
235         return getGroupType(uniqueId, false);
236
237     }
238
239     @Override
240     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupType(String uniqueId, boolean inTransaction) {
241         return getElementType(this::getGroupTypeByUid, uniqueId, inTransaction);
242     }
243
244     @Override
245     public Either<GroupTypeDefinition, StorageOperationStatus> getLatestGroupTypeByType(String type) {
246         return getLatestGroupTypeByType(type, false);
247     }
248
249     @Override
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);
254
255         return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
256
257     }
258
259     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByCriteria(String type, Map<String, Object> properties, boolean inTransaction) {
260         Either<GroupTypeDefinition, StorageOperationStatus> result = null;
261         try {
262             if (type == null || type.isEmpty()) {
263                 log.error("type is empty");
264                 result = Either.right(StorageOperationStatus.INVALID_ID);
265                 return result;
266             }
267
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()));
271             } else {
272                 GroupTypeDataDefinition dataDefinition = groupTypeEither.left().value().stream().map(e -> e.getGroupTypeDataDefinition()).findFirst().get();
273                 result = getGroupType(dataDefinition.getUniqueId(), inTransaction);
274             }
275
276             return result;
277
278         } finally {
279             handleTransactionCommitRollback(inTransaction, result);
280         }
281     }
282
283     @Override
284     public Either<GroupTypeDefinition, StorageOperationStatus> getGroupTypeByTypeAndVersion(String type, String version) {
285         return getGroupTypeByTypeAndVersion(type, version, false);
286     }
287
288     @Override
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);
293
294         return getGroupTypeByCriteria(type, mapCriteria, inTransaction);
295     }
296
297     /**
298      * Add group type to graph.
299      * <p>
300      * 1. Add group type node
301      * <p>
302      * 2. Add edge between the former node to its parent(if exists)
303      * <p>
304      * 3. Add property node and associate it to the node created at #1. (per property & if exists)
305      *
306      * @param groupTypeDefinition
307      * @return
308      */
309     private Either<GroupTypeData, TitanOperationStatus> addGroupTypeToGraph(GroupTypeDefinition groupTypeDefinition) {
310
311         log.debug("Got group type {}", groupTypeDefinition);
312
313         String ctUniqueId = UniqueIdBuilder.buildGroupTypeUid(groupTypeDefinition.getType(), groupTypeDefinition.getVersion());
314
315         GroupTypeData groupTypeData = buildGroupTypeData(groupTypeDefinition, ctUniqueId);
316
317         log.debug("Before adding group type to graph. groupTypeData = {}", groupTypeData);
318
319         Either<GroupTypeData, TitanOperationStatus> createGTResult = titanGenericDao.createNode(groupTypeData, GroupTypeData.class);
320         log.debug("After adding group type to graph. status is = {}", createGTResult);
321
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);
326         }
327
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());
334         }
335
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());
341             }
342         }
343
344         return Either.left(createGTResult.left().value());
345
346     }
347
348
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);
351
352         Either<GroupTypeData, TitanOperationStatus> derivedFromGroupTypeResult =
353                 titanGenericDao.getNode(GraphPropertiesDictionary.TYPE.getProperty(), derivedFrom, GroupTypeData.class);
354
355         if (derivedFromGroupTypeResult.isLeft()) {
356             UniqueIdData from = new UniqueIdData(NodeTypeEnum.GroupType, ctUniqueId);
357             GroupTypeData to = derivedFromGroupTypeResult.left().value();
358
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;
362         } else {
363             TitanOperationStatus status = derivedFromGroupTypeResult.right().value();
364             log.debug("Failed to found parent Group Type {}, stauts is {}.", derivedFrom, status);
365             return Either.right(status);
366         }
367     }
368
369
370     private Either<GroupTypeDefinition, StorageOperationStatus> ensureExsitanceDerivedFromEdge(GroupTypeDefinition groupTypeDefinition) {
371         Either<GroupTypeDefinition, StorageOperationStatus> result = Either.left(groupTypeDefinition);
372
373         GroupTypeData childGroupType = null;
374         GroupTypeData parentGroupType = null;
375
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);
381         } else {
382             childGroupType = childGroupTypeResult.left().value();
383         }
384
385
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);
392             } else {
393                 parentGroupType = parentGroupTypeResult.left().value();
394             }
395         }
396
397
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());
402             } else {
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()));
408                 }
409             }
410
411         }
412
413
414         return result;
415     }
416
417
418     private GroupTypeData buildGroupTypeData(GroupTypeDefinition groupTypeDefinition, String ctUniqueId) {
419
420         GroupTypeData groupTypeData = new GroupTypeData(groupTypeDefinition);
421
422         groupTypeData.getGroupTypeDataDefinition().setUniqueId(ctUniqueId);
423         Long creationDate = groupTypeData.getGroupTypeDataDefinition().getCreationTime();
424         if (creationDate == null) {
425             creationDate = System.currentTimeMillis();
426         }
427         groupTypeData.getGroupTypeDataDefinition().setCreationTime(creationDate);
428         groupTypeData.getGroupTypeDataDefinition().setModificationTime(creationDate);
429
430         return groupTypeData;
431     }
432
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));
441         }
442         String childUniqueId = getResponse.left().value().get(0).getUniqueId();
443         Set<String> travelledTypes = new HashSet<>();
444         do {
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));
453                 } else {
454                     log.debug("Derived from node is not found for type {} - this is OK for root capability.");
455                     return Either.left(false);
456                 }
457             }
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);
462             }
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);
470     }
471
472     /**
473      * FOR TEST ONLY
474      *
475      * @param propertyOperation
476      */
477     public void setPropertyOperation(PropertyOperation propertyOperation) {
478         this.propertyOperation = propertyOperation;
479     }
480
481     @Override
482     public Either<GroupTypeData, TitanOperationStatus> getLatestGroupTypeByNameFromGraph(String name) {
483
484         return null;
485     }
486
487 }