Sync Integ to Master
[sdc.git] / catalog-dao / src / main / java / org / openecomp / sdc / be / dao / jsongraph / TitanDao.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.dao.jsongraph;
22
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30
31 import org.apache.commons.collections.MapUtils;
32 import org.apache.commons.lang3.tuple.ImmutablePair;
33 import org.apache.tinkerpop.gremlin.structure.Direction;
34 import org.apache.tinkerpop.gremlin.structure.Edge;
35 import org.apache.tinkerpop.gremlin.structure.Element;
36 import org.apache.tinkerpop.gremlin.structure.Property;
37 import org.apache.tinkerpop.gremlin.structure.Vertex;
38 import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
39 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
40 import org.openecomp.sdc.be.dao.jsongraph.types.EdgePropertyEnum;
41 import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum;
42 import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum;
43 import org.openecomp.sdc.be.dao.jsongraph.utils.JsonParserUtils;
44 import org.openecomp.sdc.be.dao.titan.TitanGraphClient;
45 import org.openecomp.sdc.be.dao.titan.TitanOperationStatus;
46 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
47 import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum;
48 import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition;
49 import org.openecomp.sdc.common.jsongraph.util.CommonUtility;
50 import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53 import org.springframework.beans.factory.annotation.Qualifier;
54 import org.springframework.stereotype.Component;
55
56 import com.thinkaurelius.titan.core.PropertyKey;
57 import com.thinkaurelius.titan.core.TitanEdge;
58 import com.thinkaurelius.titan.core.TitanGraph;
59 import com.thinkaurelius.titan.core.TitanGraphQuery;
60 import com.thinkaurelius.titan.core.TitanVertex;
61 import com.thinkaurelius.titan.core.TitanVertexQuery;
62
63 import fj.data.Either;
64
65 @Component("titan-dao")
66 public class TitanDao {
67     TitanGraphClient titanClient;
68
69     private static Logger logger = LoggerFactory.getLogger(TitanDao.class.getName());
70
71     public TitanDao(@Qualifier("titan-client") TitanGraphClient titanClient) {
72         this.titanClient = titanClient;
73         logger.info("** TitanDao created");
74     }
75
76     public TitanOperationStatus commit() {
77         logger.debug("doing commit.");
78         return titanClient.commit();
79     }
80
81     public TitanOperationStatus rollback() {
82         return titanClient.rollback();
83     }
84
85     public Either<TitanGraph, TitanOperationStatus> getGraph() {
86         return titanClient.getGraph();
87     }
88
89     /**
90      * 
91      * @param graphVertex
92      * @return
93      */
94     public Either<GraphVertex, TitanOperationStatus> createVertex(GraphVertex graphVertex) {
95         logger.trace("try to create vertex for ID [{}]", graphVertex.getUniqueId());
96         Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
97         if (graph.isLeft()) {
98             try {
99                 TitanGraph tGraph = graph.left().value();
100
101                 TitanVertex vertex = tGraph.addVertex();
102
103                 setVertexProperties(vertex, graphVertex);
104
105                 graphVertex.setVertex(vertex);
106
107                 return Either.left(graphVertex);
108
109             } catch (Exception e) {
110                 logger.debug("Failed to create Node for ID [{}]", graphVertex.getUniqueId(), e);
111                 return Either.right(TitanGraphClient.handleTitanException(e));
112             }
113         } else {
114             logger.debug("Failed to create vertex for ID [{}]  {}", graphVertex.getUniqueId(), graph.right().value());
115             return Either.right(graph.right().value());
116         }
117     }
118
119     /**
120      * 
121      * @param name
122      * @param value
123      * @param label
124      * @return
125      */
126     public Either<GraphVertex, TitanOperationStatus> getVertexByPropertyAndLabel(GraphPropertyEnum name, Object value, VertexTypeEnum label) {
127         return getVertexByPropertyAndLabel(name, value, label, JsonParseFlagEnum.ParseAll);
128     }
129
130     public Either<GraphVertex, TitanOperationStatus> getVertexByLabel(VertexTypeEnum label) {
131         return titanClient.getGraph().left().map(graph -> graph.query().has(GraphPropertyEnum.LABEL.getProperty(), label.getName()).vertices()).left().bind(titanVertices -> getFirstFoundVertex(JsonParseFlagEnum.NoParse, titanVertices));
132     }
133
134     private Either<GraphVertex, TitanOperationStatus> getFirstFoundVertex(JsonParseFlagEnum parseFlag, Iterable<TitanVertex> vertices) {
135         Iterator<TitanVertex> iterator = vertices.iterator();
136         if (iterator.hasNext()) {
137             TitanVertex vertex = iterator.next();
138             GraphVertex graphVertex = createAndFill(vertex, parseFlag);
139
140             return Either.left(graphVertex);
141         }
142         return Either.right(TitanOperationStatus.NOT_FOUND);
143     }
144
145     /**
146      * 
147      * @param name
148      * @param value
149      * @param label
150      * @param parseFlag
151      * @return
152      */
153     public Either<GraphVertex, TitanOperationStatus> getVertexByPropertyAndLabel(GraphPropertyEnum name, Object value, VertexTypeEnum label, JsonParseFlagEnum parseFlag) {
154
155         Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
156         if (graph.isLeft()) {
157             try {
158                 TitanGraph tGraph = graph.left().value();
159
160                 @SuppressWarnings("unchecked")
161                 Iterable<TitanVertex> vertecies = tGraph.query().has(name.getProperty(), value).has(GraphPropertyEnum.LABEL.getProperty(), label.getName()).vertices();
162
163                 java.util.Iterator<TitanVertex> iterator = vertecies.iterator();
164                 if (iterator.hasNext()) {
165                     TitanVertex vertex = iterator.next();
166                     GraphVertex graphVertex = createAndFill(vertex, parseFlag);
167
168                     return Either.left(graphVertex);
169                 }
170                 if (logger.isDebugEnabled()) {
171                     logger.debug("No vertex in graph for key = {}  and value = {}   label = {}" + name, value, label);
172                 }
173                 return Either.right(TitanOperationStatus.NOT_FOUND);
174             } catch (Exception e) {
175                 if (logger.isDebugEnabled()) {
176                     logger.debug("Failed to get vertex in graph for key ={} and value = {}  label = {}", name, value, label);
177                 }
178                 return Either.right(TitanGraphClient.handleTitanException(e));
179             }
180
181         } else {
182             if (logger.isDebugEnabled()) {
183                 logger.debug("No vertex in graph for key ={} and value = {}  label = {} error :{}", name, value, label, graph.right().value());
184             }
185             return Either.right(graph.right().value());
186         }
187     }
188
189     /**
190      * 
191      * @param id
192      * @return
193      */
194     public Either<GraphVertex, TitanOperationStatus> getVertexById(String id) {
195         return getVertexById(id, JsonParseFlagEnum.ParseAll);
196     }
197
198     /**
199      * 
200      * @param id
201      * @param parseFlag
202      * @return
203      */
204     public Either<GraphVertex, TitanOperationStatus> getVertexById(String id, JsonParseFlagEnum parseFlag) {
205
206         Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
207         if (id == null) {
208             if (logger.isDebugEnabled()) {
209                 logger.debug("No vertex in graph for id = {} ", id);
210             }
211             return Either.right(TitanOperationStatus.NOT_FOUND);
212         }
213         if (graph.isLeft()) {
214             try {
215                 TitanGraph tGraph = graph.left().value();
216
217                 @SuppressWarnings("unchecked")
218                 Iterable<TitanVertex> vertecies = tGraph.query().has(GraphPropertyEnum.UNIQUE_ID.getProperty(), id).vertices();
219
220                 java.util.Iterator<TitanVertex> iterator = vertecies.iterator();
221                 if (iterator.hasNext()) {
222                     TitanVertex vertex = iterator.next();
223                     GraphVertex graphVertex = createAndFill(vertex, parseFlag);
224                     return Either.left(graphVertex);
225                 } else {
226                     if (logger.isDebugEnabled()) {
227                         logger.debug("No vertex in graph for id = {}", id);
228                     }
229                     return Either.right(TitanOperationStatus.NOT_FOUND);
230                 }
231             } catch (Exception e) {
232                 if (logger.isDebugEnabled()) {
233                     logger.debug("Failed to get vertex in graph for id {} ", id);
234                 }
235                 return Either.right(TitanGraphClient.handleTitanException(e));
236             }
237         } else {
238             if (logger.isDebugEnabled()) {
239                 logger.debug("No vertex in graph for id {} error : {}", id, graph.right().value());
240             }
241             return Either.right(graph.right().value());
242         }
243     }
244
245     private void setVertexProperties(TitanVertex vertex, GraphVertex graphVertex) throws IOException {
246
247         if (graphVertex.getMetadataProperties() != null) {
248             for (Map.Entry<GraphPropertyEnum, Object> entry : graphVertex.getMetadataProperties().entrySet()) {
249                 if (entry.getValue() != null) {
250                     vertex.property(entry.getKey().getProperty(), entry.getValue());
251                 }
252             }
253         }
254         vertex.property(GraphPropertyEnum.LABEL.getProperty(), graphVertex.getLabel().getName());
255
256         Map<String, ? extends ToscaDataDefinition> json = graphVertex.getJson();
257         if (json != null) {
258             String jsonStr = JsonParserUtils.toJson(json);
259             vertex.property(GraphPropertyEnum.JSON.getProperty(), jsonStr);
260
261         }
262         Map<String, Object> jsonMetadata = graphVertex.getMetadataJson();
263         if (jsonMetadata != null) {
264             String jsonMetadataStr = JsonParserUtils.toJson(jsonMetadata);
265             vertex.property(GraphPropertyEnum.METADATA.getProperty(), jsonMetadataStr);
266         }
267     }
268
269     public void setVertexProperties(Vertex vertex, Map<String, Object> properties) throws IOException {
270         for (Map.Entry<String, Object> entry : properties.entrySet()) {
271             if (entry.getValue() != null) {
272                 vertex.property(entry.getKey(), entry.getValue());
273             }
274         }
275     }
276
277     private GraphVertex createAndFill(TitanVertex vertex, JsonParseFlagEnum parseFlag) {
278         GraphVertex graphVertex = new GraphVertex();
279         graphVertex.setVertex(vertex);
280         parseVertexProperties(graphVertex, parseFlag);
281         return graphVertex;
282     }
283
284     public void parseVertexProperties(GraphVertex graphVertex, JsonParseFlagEnum parseFlag) {
285         TitanVertex vertex = graphVertex.getVertex();
286         Map<GraphPropertyEnum, Object> properties = getVertexProperties(vertex);
287         VertexTypeEnum label = VertexTypeEnum.getByName((String) (properties.get(GraphPropertyEnum.LABEL)));
288         for (Map.Entry<GraphPropertyEnum, Object> entry : properties.entrySet()) {
289             GraphPropertyEnum key = entry.getKey();
290             switch (key) {
291             case UNIQUE_ID:
292                 graphVertex.setUniqueId((String) entry.getValue());
293                 break;
294             case LABEL:
295                 graphVertex.setLabel(VertexTypeEnum.getByName((String) entry.getValue()));
296                 break;
297             case COMPONENT_TYPE:
298                 String type = (String) entry.getValue();
299                 if (type != null) {
300                     graphVertex.setType(ComponentTypeEnum.valueOf(type));
301                 }
302                 break;
303             case JSON:
304                 if (parseFlag == JsonParseFlagEnum.ParseAll || parseFlag == JsonParseFlagEnum.ParseJson) {
305                     String json = (String) entry.getValue();
306                     Map<String, ? extends ToscaDataDefinition> jsonObj = JsonParserUtils.toMap(json, label.getClassOfJson());
307                     graphVertex.setJson(jsonObj);
308                 }
309                 break;
310             case METADATA:
311                 if (parseFlag == JsonParseFlagEnum.ParseAll || parseFlag == JsonParseFlagEnum.ParseMetadata) {
312                     String json = (String) entry.getValue();
313                     Map<String, Object> metadatObj = JsonParserUtils.toMap(json);
314                     graphVertex.setMetadataJson(metadatObj);
315                 }
316                 break;
317             default:
318                 graphVertex.addMetadataProperty(key, entry.getValue());
319                 break;
320             }
321         }
322     }
323
324     public TitanOperationStatus createEdge(GraphVertex from, GraphVertex to, EdgeLabelEnum label, Map<EdgePropertyEnum, Object> properties) {
325         return createEdge(from.getVertex(), to.getVertex(), label, properties);
326     }
327
328     public TitanOperationStatus createEdge(Vertex from, Vertex to, EdgeLabelEnum label, Map<EdgePropertyEnum, Object> properties) {
329         if (logger.isTraceEnabled()) {
330             logger.trace("Try to connect {} with {} label {} properties {}", from.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), to.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), label, properties);
331         }
332         if (from == null || to == null) {
333             logger.trace("No Titan vertex for id from {} or id to {}", from.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), to.property(GraphPropertyEnum.UNIQUE_ID.getProperty()));
334             return TitanOperationStatus.NOT_FOUND;
335         }
336         Edge edge = from.addEdge(label.name(), to);
337         setEdgeProperties(edge, properties);
338         return TitanOperationStatus.OK;
339     }
340
341     public Map<GraphPropertyEnum, Object> getVertexProperties(Element element) {
342
343         Map<GraphPropertyEnum, Object> result = new HashMap<GraphPropertyEnum, Object>();
344
345         if (element != null && element.keys() != null && element.keys().size() > 0) {
346             Map<String, Property> propertyMap = ElementHelper.propertyMap(element, element.keys().toArray(new String[element.keys().size()]));
347
348             for (Entry<String, Property> entry : propertyMap.entrySet()) {
349                 String key = entry.getKey();
350                 Object value = entry.getValue().value();
351
352                 GraphPropertyEnum valueOf = GraphPropertyEnum.getByProperty(key);
353                 if (valueOf != null) {
354                     result.put(valueOf, value);
355                 }
356             }
357         }
358         return result;
359     }
360
361     public Map<EdgePropertyEnum, Object> getEdgeProperties(Element element) {
362
363         Map<EdgePropertyEnum, Object> result = new HashMap<EdgePropertyEnum, Object>();
364
365         if (element != null && element.keys() != null && element.keys().size() > 0) {
366             Map<String, Property> propertyMap = ElementHelper.propertyMap(element, element.keys().toArray(new String[element.keys().size()]));
367
368             for (Entry<String, Property> entry : propertyMap.entrySet()) {
369                 String key = entry.getKey();
370                 Object value = entry.getValue().value();
371
372                 EdgePropertyEnum valueOf = EdgePropertyEnum.getByProperty(key);
373                 if (valueOf != null) {
374                     result.put(valueOf, value);
375                 }
376             }
377         }
378         return result;
379     }
380
381     public void setEdgeProperties(Element element, Map<EdgePropertyEnum, Object> properties) {
382
383         if (properties != null && !properties.isEmpty()) {
384
385             Object[] propertyKeyValues = new Object[properties.size() * 2];
386             int i = 0;
387             for (Entry<EdgePropertyEnum, Object> entry : properties.entrySet()) {
388                 propertyKeyValues[i++] = entry.getKey().getProperty();
389                 propertyKeyValues[i++] = entry.getValue();
390             }
391
392             ElementHelper.attachProperties(element, propertyKeyValues);
393
394         }
395
396     }
397
398     public Either<List<GraphVertex>, TitanOperationStatus> getByCriteria(VertexTypeEnum type, Map<GraphPropertyEnum, Object> props) {
399         return getByCriteria(type, props, JsonParseFlagEnum.ParseAll);
400     }
401
402     public Either<List<GraphVertex>, TitanOperationStatus> getByCriteria(VertexTypeEnum type, Map<GraphPropertyEnum, Object> props, JsonParseFlagEnum parseFlag) {
403         Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
404         if (graph.isLeft()) {
405             try {
406                 TitanGraph tGraph = graph.left().value();
407
408                 TitanGraphQuery<? extends TitanGraphQuery> query = tGraph.query();
409                 if (type != null) {
410                     query = query.has(GraphPropertyEnum.LABEL.getProperty(), type.getName());
411                 }
412
413                 if (props != null && !props.isEmpty()) {
414                     for (Map.Entry<GraphPropertyEnum, Object> entry : props.entrySet()) {
415                         query = query.has(entry.getKey().getProperty(), entry.getValue());
416                     }
417                 }
418                 Iterable<TitanVertex> vertices = query.vertices();
419                 if (vertices == null) {
420                     return Either.right(TitanOperationStatus.NOT_FOUND);
421                 }
422
423                 Iterator<TitanVertex> iterator = vertices.iterator();
424                 List<GraphVertex> result = new ArrayList<GraphVertex>();
425
426                 while (iterator.hasNext()) {
427                     TitanVertex vertex = iterator.next();
428
429                     Map<GraphPropertyEnum, Object> newProp = getVertexProperties(vertex);
430                     GraphVertex graphVertex = createAndFill(vertex, parseFlag);
431
432                     result.add(graphVertex);
433                 }
434                 if (logger.isDebugEnabled()) {
435                     logger.debug("Number of fetced nodes in graph for criteria : from type = {} and properties = {} is {}", type, props, result.size());
436                 }
437                 if (result.size() == 0) {
438                     return Either.right(TitanOperationStatus.NOT_FOUND);
439                 }
440
441                 return Either.left(result);
442             } catch (Exception e) {
443                 if (logger.isDebugEnabled()) {
444                     logger.debug("Failed  get by  criteria for type = {} and properties = {}", type, props, e);
445                 }
446                 return Either.right(TitanGraphClient.handleTitanException(e));
447             }
448
449         } else {
450             if (logger.isDebugEnabled()) {
451                 logger.debug("Failed  get by  criteria for type ={} and properties = {} error : {}", type, props, graph.right().value());
452             }
453             return Either.right(graph.right().value());
454         }
455     }
456
457     public Either<List<GraphVertex>, TitanOperationStatus> getByCriteria(VertexTypeEnum type, Map<GraphPropertyEnum, Object> props, Map<GraphPropertyEnum, Object> hasNotProps, JsonParseFlagEnum parseFlag) {
458         Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
459         if (graph.isLeft()) {
460             try {
461                 TitanGraph tGraph = graph.left().value();
462
463                 TitanGraphQuery<? extends TitanGraphQuery> query = tGraph.query();
464                 if (type != null) {
465                     query = query.has(GraphPropertyEnum.LABEL.getProperty(), type.getName());
466                 }
467
468                 if (props != null && !props.isEmpty()) {
469                     for (Map.Entry<GraphPropertyEnum, Object> entry : props.entrySet()) {
470                         query = query.has(entry.getKey().getProperty(), entry.getValue());
471                     }
472                 }
473                 if (hasNotProps != null && !hasNotProps.isEmpty()) {
474                     for (Map.Entry<GraphPropertyEnum, Object> entry : hasNotProps.entrySet()) {
475                         if (entry.getValue() instanceof List) {
476                             buildMultipleNegateQueryFromList(entry, query);
477                         } else {
478                             query = query.hasNot(entry.getKey().getProperty(), entry.getValue());
479                         }
480                     }
481                 }
482                 Iterable<TitanVertex> vertices = query.vertices();
483                 if (vertices == null) {
484                     return Either.right(TitanOperationStatus.NOT_FOUND);
485                 }
486
487                 Iterator<TitanVertex> iterator = vertices.iterator();
488                 List<GraphVertex> result = new ArrayList<GraphVertex>();
489
490                 while (iterator.hasNext()) {
491                     TitanVertex vertex = iterator.next();
492
493                     Map<GraphPropertyEnum, Object> newProp = getVertexProperties(vertex);
494                     GraphVertex graphVertex = createAndFill(vertex, parseFlag);
495
496                     result.add(graphVertex);
497                 }
498                 if (logger.isDebugEnabled()) {
499                     logger.debug("Number of fetced nodes in graph for criteria : from type = {} and properties = {} is {}", type, props, result.size());
500                 }
501                 if (result.size() == 0) {
502                     return Either.right(TitanOperationStatus.NOT_FOUND);
503                 }
504
505                 return Either.left(result);
506             } catch (Exception e) {
507                 if (logger.isDebugEnabled()) {
508                     logger.debug("Failed  get by  criteria for type = {} and properties = {}", type, props, e);
509                 }
510                 return Either.right(TitanGraphClient.handleTitanException(e));
511             }
512
513         } else {
514             if (logger.isDebugEnabled()) {
515                 logger.debug("Failed  get by  criteria for type ={} and properties = {} error : {}", type, props, graph.right().value());
516             }
517             return Either.right(graph.right().value());
518         }
519     }
520
521     public Either<Iterator<Vertex>, TitanOperationStatus> getCatalogVerticies() {
522         Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
523         if (graph.isLeft()) {
524             try {
525                 TitanGraph tGraph = graph.left().value();
526
527                 Iterable<TitanVertex> vCatalogIter = tGraph.query().has(GraphPropertyEnum.LABEL.getProperty(), VertexTypeEnum.CATALOG_ROOT.getName()).vertices();
528                 if (vCatalogIter == null) {
529                     logger.debug("Failed to fetch catalog vertex");
530                     return Either.right(TitanOperationStatus.GENERAL_ERROR);
531                 }
532                 TitanVertex catalogV = vCatalogIter.iterator().next();
533                 if (catalogV == null) {
534                     logger.debug("Failed to fetch catalog vertex");
535                     return Either.right(TitanOperationStatus.GENERAL_ERROR);
536                 }
537                 Iterator<Vertex> vertices = catalogV.vertices(Direction.OUT, EdgeLabelEnum.CATALOG_ELEMENT.name());
538
539                 return Either.left(vertices);
540             } catch (Exception e) {
541                 if (logger.isDebugEnabled()) {
542                     logger.debug("Failed  get by  criteria: ", e);
543                 }
544                 return Either.right(TitanGraphClient.handleTitanException(e));
545             }
546
547         } else {
548             if (logger.isDebugEnabled()) {
549                 logger.debug("Failed  get by  criteria : ", graph.right().value());
550             }
551             return Either.right(graph.right().value());
552         }
553     }
554
555     private void buildMultipleNegateQueryFromList(Map.Entry<GraphPropertyEnum, Object> entry, TitanGraphQuery query) {
556         List<Object> negateList = (List<Object>) entry.getValue();
557         for (Object listItem : negateList) {
558             query.hasNot(entry.getKey().getProperty(), listItem);
559         }
560     }
561
562     /**
563      * 
564      * @param parentVertex
565      * @param edgeLabel
566      * @param parseFlag
567      * @return
568      */
569     public Either<GraphVertex, TitanOperationStatus> getChildVertex(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
570         Either<List<GraphVertex>, TitanOperationStatus> childrenVertecies = getChildrenVertecies(parentVertex, edgeLabel, parseFlag);
571         if (childrenVertecies.isRight()) {
572             return Either.right(childrenVertecies.right().value());
573         }
574         return Either.left(childrenVertecies.left().value().get(0));
575     }
576
577     /**
578      *
579      * @param parentVertex
580      * @param edgeLabel
581      * @param parseFlag
582      * @return
583      */
584     public Either<Vertex, TitanOperationStatus> getChildVertex(Vertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
585         Either<List<Vertex>, TitanOperationStatus> childrenVertecies = getChildrenVertecies(parentVertex, edgeLabel, parseFlag);
586         if (childrenVertecies.isRight()) {
587             return Either.right(childrenVertecies.right().value());
588         }
589         return Either.left(childrenVertecies.left().value().get(0));
590     }
591
592     public Either<GraphVertex, TitanOperationStatus> getParentVertex(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
593         Either<List<GraphVertex>, TitanOperationStatus> childrenVertecies = getParentVertecies(parentVertex, edgeLabel, parseFlag);
594         if (childrenVertecies.isRight()) {
595             return Either.right(childrenVertecies.right().value());
596         }
597         return Either.left(childrenVertecies.left().value().get(0));
598     }
599
600     public Either<Vertex, TitanOperationStatus> getParentVertex(Vertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
601         Either<List<Vertex>, TitanOperationStatus> childrenVertecies = getParentVertecies(parentVertex, edgeLabel, parseFlag);
602         if (childrenVertecies.isRight()) {
603             return Either.right(childrenVertecies.right().value());
604         }
605         return Either.left(childrenVertecies.left().value().get(0));
606     }
607
608     /**
609      * 
610      * @param parentVertex
611      * @param edgeLabel
612      * @param parseFlag
613      * @return
614      */
615     public Either<List<GraphVertex>, TitanOperationStatus> getChildrenVertecies(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
616         return getAdjacentVerticies(parentVertex, edgeLabel, parseFlag, Direction.OUT);
617     }
618
619     public Either<List<GraphVertex>, TitanOperationStatus> getParentVertecies(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
620         return getAdjacentVerticies(parentVertex, edgeLabel, parseFlag, Direction.IN);
621     }
622
623     public Either<List<Vertex>, TitanOperationStatus> getParentVertecies(Vertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
624         return getAdjacentVerticies(parentVertex, edgeLabel, parseFlag, Direction.IN);
625     }
626
627     private Either<List<Vertex>, TitanOperationStatus> getAdjacentVerticies(Vertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag, Direction direction) {
628         List<Vertex> list = new ArrayList<>();
629         try {
630             Either<TitanGraph, TitanOperationStatus> graphRes = titanClient.getGraph();
631             if (graphRes.isRight()) {
632                 logger.error("Failed to retrieve graph. status is {}", graphRes);
633                 return Either.right(graphRes.right().value());
634             }
635             Iterator<Edge> edgesCreatorIterator = parentVertex.edges(direction, edgeLabel.name());
636             if (edgesCreatorIterator != null) {
637                 while (edgesCreatorIterator.hasNext()) {
638                     Edge edge = edgesCreatorIterator.next();
639                     TitanVertex vertex;
640                     if (direction == Direction.IN) {
641                         vertex = (TitanVertex) edge.outVertex();
642                     } else {
643                         vertex = (TitanVertex) edge.inVertex();
644                     }
645                     // GraphVertex graphVertex = createAndFill(vertex, parseFlag);
646
647                     list.add(vertex);
648                 }
649             }
650             if (true == list.isEmpty()) {
651                 return Either.right(TitanOperationStatus.NOT_FOUND);
652             }
653         } catch (Exception e) {
654             logger.error("Failed to perform graph operation ", e);
655             Either.right(TitanGraphClient.handleTitanException(e));
656         }
657
658         return Either.left(list);
659     }
660
661     /**
662      *
663      * @param parentVertex
664      * @param edgeLabel
665      * @param parseFlag
666      * @return
667      */
668     public Either<List<Vertex>, TitanOperationStatus> getChildrenVertecies(Vertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
669         return getAdjacentVerticies(parentVertex, edgeLabel, parseFlag, Direction.OUT);
670     }
671
672     private Either<List<GraphVertex>, TitanOperationStatus> getAdjacentVerticies(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag, Direction direction) {
673         List<GraphVertex> list = new ArrayList<GraphVertex>();
674
675         Either<List<Vertex>, TitanOperationStatus> adjacentVerticies = getAdjacentVerticies(parentVertex.getVertex(), edgeLabel, parseFlag, direction);
676         if (adjacentVerticies.isRight()) {
677             return Either.right(adjacentVerticies.right().value());
678         }
679         adjacentVerticies.left().value().stream().forEach(vertex -> {
680             list.add(createAndFill((TitanVertex) vertex, parseFlag));
681         });
682
683         return Either.left(list);
684     }
685
686     /**
687      * Searches Edge by received label and criteria
688      * 
689      * @param vertex
690      * @param label
691      * @param properties
692      * @return found edge or TitanOperationStatus
693      */
694     public Either<Edge, TitanOperationStatus> getBelongingEdgeByCriteria(GraphVertex vertex, EdgeLabelEnum label, Map<GraphPropertyEnum, Object> properties) {
695
696         Either<Edge, TitanOperationStatus> result = null;
697         Edge matchingEdge = null;
698         String notFoundMsg = "No edges in graph for criteria";
699         try {
700             TitanVertexQuery<?> query = vertex.getVertex().query().labels(label.name());
701
702             if (properties != null && !properties.isEmpty()) {
703                 for (Map.Entry<GraphPropertyEnum, Object> entry : properties.entrySet()) {
704                     query = query.has(entry.getKey().getProperty(), entry.getValue());
705                 }
706             }
707
708             Iterable<TitanEdge> edges = query.edges();
709             if (edges == null) {
710                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, notFoundMsg);
711                 result = Either.right(TitanOperationStatus.NOT_FOUND);
712             } else {
713                 Iterator<TitanEdge> eIter = edges.iterator();
714                 if (eIter.hasNext()) {
715                     matchingEdge = eIter.next();
716                 } else {
717                     CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, notFoundMsg);
718                     result = Either.right(TitanOperationStatus.NOT_FOUND);
719                 }
720             }
721             if (result == null) {
722                 result = Either.left(matchingEdge);
723             }
724         } catch (Exception e) {
725             CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during getting edge by criteria for component with id {}. {}", vertex.getUniqueId(), e);
726             return Either.right(TitanGraphClient.handleTitanException(e));
727         }
728         return result;
729     }
730
731     /**
732      * Deletes Edge by received label and criteria
733      * 
734      * @param vertex
735      * @param label
736      * @param properties
737      * @return
738      */
739     public Either<Edge, TitanOperationStatus> deleteBelongingEdgeByCriteria(GraphVertex vertex, EdgeLabelEnum label, Map<GraphPropertyEnum, Object> properties) {
740         Either<Edge, TitanOperationStatus> result = null;
741         try {
742             result = getBelongingEdgeByCriteria(vertex, label, properties);
743             if (result.isLeft()) {
744                 Edge edge = result.left().value();
745                 CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to delete an edge with the label {} belonging to the vertex {} ", label.name(), vertex.getUniqueId());
746                 edge.remove();
747                 result = Either.left(edge);
748             } else {
749                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to find an edge with the label {} belonging to the vertex {} ", label.name(), vertex.getUniqueId());
750             }
751         } catch (Exception e) {
752             CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleting an edge by criteria for the component with id {}. {}", vertex.getUniqueId(), e);
753             return Either.right(TitanGraphClient.handleTitanException(e));
754         }
755         return result;
756     }
757
758     @SuppressWarnings("unchecked")
759     /**
760      * Deletes an edge between vertices fromVertex and toVertex according to received label
761      * 
762      * @param fromVertex
763      * @param toVertex
764      * @param label
765      * @return
766      */
767
768     public Either<Edge, TitanOperationStatus> deleteEdge(GraphVertex fromVertex, GraphVertex toVertex, EdgeLabelEnum label) {
769         return deleteEdge(fromVertex.getVertex(), toVertex.getVertex(), label, fromVertex.getUniqueId(), toVertex.getUniqueId());
770     }
771
772     public Either<Edge, TitanOperationStatus> deleteEdge(TitanVertex fromVertex, TitanVertex toVertex, EdgeLabelEnum label, String uniqueIdFrom, String uniqueIdTo) {
773         Either<Edge, TitanOperationStatus> result = null;
774         try {
775             Iterable<TitanEdge> edges = fromVertex.query().labels(label.name()).edges();
776             Iterator<TitanEdge> eIter = edges.iterator();
777             while (eIter.hasNext()) {
778                 Edge edge = eIter.next();
779                 String currVertexUniqueId = edge.inVertex().value(GraphPropertyEnum.UNIQUE_ID.getProperty());
780                 if (currVertexUniqueId != null && currVertexUniqueId.equals(uniqueIdTo)) {
781                     CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to delete an edge with the label {} between vertices {} and {}. ", label.name(), uniqueIdFrom, uniqueIdTo);
782                     edge.remove();
783                     result = Either.left(edge);
784                     break;
785                 }
786             }
787             if (result == null) {
788                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete an edge with the label {} between vertices {} and {}. ", label.name(), uniqueIdFrom, uniqueIdTo);
789                 result = Either.right(TitanOperationStatus.NOT_FOUND);
790             }
791         } catch (Exception e) {
792             CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleting an edge with the label {} between vertices {} and {}. {}", label.name(), uniqueIdFrom, uniqueIdTo, e);
793             return Either.right(TitanGraphClient.handleTitanException(e));
794         }
795         return result;
796     }
797
798     public TitanOperationStatus deleteEdgeByDirection(GraphVertex fromVertex, Direction direction, EdgeLabelEnum label) {
799         try {
800             Iterator<Edge> edges = fromVertex.getVertex().edges(direction, label.name());
801
802             while (edges.hasNext()) {
803                 Edge edge = edges.next();
804                 edge.remove();
805             }
806         } catch (Exception e) {
807             logger.debug("Failed to remove from vertex {} edges {} by direction {} ", fromVertex.getUniqueId(), label, direction, e);
808             return TitanGraphClient.handleTitanException(e);
809         }
810         return TitanOperationStatus.OK;
811     }
812
813     /**
814      * Updates vertex properties. Note that graphVertex argument should contain updated data
815      * 
816      * @param graphVertex
817      * @return
818      */
819     public Either<GraphVertex, TitanOperationStatus> updateVertex(GraphVertex graphVertex) {
820         CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to update metadata of vertex with uniqueId {}. ", graphVertex.getUniqueId());
821         try {
822             graphVertex.updateMetadataJsonWithCurrentMetadataProperties();
823             setVertexProperties(graphVertex.getVertex(), graphVertex);
824
825         } catch (Exception e) {
826             CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update metadata of vertex with uniqueId {}. ", graphVertex.getUniqueId(), e);
827             return Either.right(TitanGraphClient.handleTitanException(e));
828         }
829         return Either.left(graphVertex);
830     }
831
832     /**
833      * Fetches vertices by uniqueId according to received parse flag
834      * 
835      * @param verticesToGet
836      * @return
837      */
838     public Either<Map<String, GraphVertex>, TitanOperationStatus> getVerticesByUniqueIdAndParseFlag(Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> verticesToGet) {
839
840         Either<Map<String, GraphVertex>, TitanOperationStatus> result = null;
841         Map<String, GraphVertex> vertices = new HashMap<>();
842         TitanOperationStatus titatStatus;
843         Either<GraphVertex, TitanOperationStatus> getVertexRes = null;
844         for (Map.Entry<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> entry : verticesToGet.entrySet()) {
845             if (entry.getValue().getKey() == GraphPropertyEnum.UNIQUE_ID) {
846                 getVertexRes = getVertexById(entry.getKey(), entry.getValue().getValue());
847             } else if (entry.getValue().getKey() == GraphPropertyEnum.USERID) {
848                 getVertexRes = getVertexByPropertyAndLabel(entry.getValue().getKey(), entry.getKey(), VertexTypeEnum.USER, entry.getValue().getValue());
849             }
850             if (getVertexRes == null) {
851                 titatStatus = TitanOperationStatus.ILLEGAL_ARGUMENT;
852                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Invalid vertex type label {} has been received. ", entry.getValue().getKey(), titatStatus);
853                 result = Either.right(titatStatus);
854             }
855             if (getVertexRes.isRight()) {
856                 titatStatus = getVertexRes.right().value();
857                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to get vertex by id {} . Status is {}. ", entry.getKey(), titatStatus);
858                 result = Either.right(titatStatus);
859                 break;
860             } else {
861                 vertices.put(entry.getKey(), getVertexRes.left().value());
862             }
863         }
864         if (result == null) {
865             result = Either.left(vertices);
866         }
867         return result;
868     }
869
870     /**
871      * Creates edge between "from" and "to" vertices with specified label and properties extracted from received edge
872      * 
873      * @param from
874      * @param to
875      * @param label
876      * @param edgeToCopy
877      * @return
878      */
879     public TitanOperationStatus createEdge(Vertex from, Vertex to, EdgeLabelEnum label, Edge edgeToCopy) {
880         return createEdge(from, to, label, getEdgeProperties(edgeToCopy));
881     }
882
883     public TitanOperationStatus replaceEdgeLabel(Vertex fromVertex, Vertex toVertex, Edge prevEdge, EdgeLabelEnum prevLabel, EdgeLabelEnum newLabel) {
884
885         CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to replace edge with label {} to {} between vertices {} and {}", prevLabel, newLabel, fromVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()),
886                 toVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()));
887         TitanOperationStatus result = createEdge(fromVertex, toVertex, newLabel, prevEdge);
888         if (result == TitanOperationStatus.OK) {
889             prevEdge.remove();
890         }
891         return result;
892     }
893
894     /**
895      * Replaces previous label of edge with new label
896      * 
897      * @param fromVertex
898      * @param toVertex
899      * @param prevLabel
900      * @param newLabel
901      * @return
902      */
903     public TitanOperationStatus replaceEdgeLabel(Vertex fromVertex, Vertex toVertex, EdgeLabelEnum prevLabel, EdgeLabelEnum newLabel) {
904
905         TitanOperationStatus result = null;
906         Iterator<Edge> prevEdgeIter = toVertex.edges(Direction.IN, prevLabel.name());
907         if (prevEdgeIter == null || !prevEdgeIter.hasNext()) {
908             CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to replace edge with label {} to {} between vertices {} and {}", prevLabel, newLabel, fromVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()),
909                     toVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()));
910             result = TitanOperationStatus.NOT_FOUND;
911         }
912         if (result == null) {
913             result = replaceEdgeLabel(fromVertex, toVertex, prevEdgeIter.next(), prevLabel, newLabel);
914         }
915         return result;
916     }
917
918     /**
919      * Updates metadata properties of vertex on graph. Json metadata property of the vertex will be updated with received properties too.
920      * 
921      * 
922      * @param vertex
923      * @param properties
924      * @return
925      */
926     public TitanOperationStatus updateVertexMetadataPropertiesWithJson(Vertex vertex, Map<GraphPropertyEnum, Object> properties) {
927         try {
928             if (!MapUtils.isEmpty(properties)) {
929                 String jsonMetadataStr = (String) vertex.property(GraphPropertyEnum.METADATA.getProperty()).value();
930                 Map<String, Object> jsonMetadataMap = JsonParserUtils.toMap(jsonMetadataStr);
931                 for (Map.Entry<GraphPropertyEnum, Object> property : properties.entrySet()) {
932                     vertex.property(property.getKey().getProperty(), property.getValue());
933                     jsonMetadataMap.put(property.getKey().getProperty(), property.getValue());
934                 }
935                 vertex.property(GraphPropertyEnum.METADATA.getProperty(), JsonParserUtils.toJson(jsonMetadataMap));
936             }
937         } catch (Exception e) {
938             CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occurred during update vertex metadata properties with json{}. {}", vertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), e.getMessage());
939             return TitanGraphClient.handleTitanException(e);
940         }
941         return TitanOperationStatus.OK;
942     }
943
944     public TitanOperationStatus disassociateAndDeleteLast(GraphVertex vertex, Direction direction, EdgeLabelEnum label) {
945         try {
946             Iterator<Edge> edges = vertex.getVertex().edges(direction, label.name());
947
948             while (edges.hasNext()) {
949                 Edge edge = edges.next();
950                 Vertex secondVertex;
951                 Direction reverseDirection;
952                 if (direction == Direction.IN) {
953                     secondVertex = edge.outVertex();
954                     reverseDirection = Direction.OUT;
955                 } else {
956                     secondVertex = edge.inVertex();
957                     reverseDirection = Direction.IN;
958                 }
959                 edge.remove();
960                 CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Edge  {} with direction {} was removed from {}", label.name(), direction, vertex.getVertex());
961
962                 Iterator<Edge> restOfEdges = secondVertex.edges(reverseDirection, label.name());
963                 if (restOfEdges.hasNext() == false) {
964                     secondVertex.remove();
965                     CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "This was last edge . Vertex  {} was removed ", vertex.getUniqueId());
966                 }
967             }
968         } catch (Exception e) {
969             CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleting an edge with the label {} direction {} from vertex {}. {}", label.name(), direction, vertex.getUniqueId(), e);
970             return TitanGraphClient.handleTitanException(e);
971         }
972         return TitanOperationStatus.OK;
973     }
974
975     public Object getProperty(TitanVertex vertex, String key) {
976         PropertyKey propertyKey = titanClient.getGraph().left().value().getPropertyKey(key);
977         Object value = vertex.valueOrNull(propertyKey);
978         return value;
979     }
980
981     public Object getProperty(Edge edge, EdgePropertyEnum key) {
982         Object value = null;
983         try {
984             Property<Object> property = edge.property(key.getProperty());
985             if (property != null) {
986                 return property.orElse(null);
987             }
988         } catch (Exception e) {
989
990         }
991         return value;
992     }
993
994     /**
995      * 
996      * @param vertexA
997      * @param vertexB
998      * @param label
999      * @param direction
1000      * @return
1001      */
1002     public TitanOperationStatus moveEdge(GraphVertex vertexA, GraphVertex vertexB, EdgeLabelEnum label, Direction direction) {
1003         TitanOperationStatus result = deleteEdgeByDirection(vertexA, direction, label);
1004         if (result != TitanOperationStatus.OK) {
1005             logger.error("Failed to diassociate {} from element {}. error {} ", label, vertexA.getUniqueId(), result);
1006             return result;
1007         }
1008         TitanOperationStatus createRelation;
1009         if (direction == Direction.IN) {
1010             createRelation = createEdge(vertexB, vertexA, label, null);
1011         } else {
1012             createRelation = createEdge(vertexA, vertexB, label, null);
1013         }
1014         if (createRelation != TitanOperationStatus.OK) {
1015             return createRelation;
1016         }
1017         return TitanOperationStatus.OK;
1018     }
1019
1020     public Either<Edge, TitanOperationStatus> getBelongingEdgeByCriteria(String parentId, EdgeLabelEnum label, Map<GraphPropertyEnum, Object> properties) {
1021         Either<GraphVertex, TitanOperationStatus> getVertexRes = getVertexById(parentId, JsonParseFlagEnum.NoParse);
1022         if (getVertexRes.isRight()) {
1023             return Either.right(getVertexRes.right().value());
1024         }
1025         return getBelongingEdgeByCriteria(getVertexRes.left().value(), label, properties);
1026     }
1027 }