[SDC] rebase 1710 code
[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         /**
131          * 
132          * @param name
133          * @param value
134          * @param label
135          * @param parseFlag
136          * @return
137          */
138         public Either<GraphVertex, TitanOperationStatus> getVertexByPropertyAndLabel(GraphPropertyEnum name, Object value, VertexTypeEnum label, JsonParseFlagEnum parseFlag) {
139
140                 Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
141                 if (graph.isLeft()) {
142                         try {
143                                 TitanGraph tGraph = graph.left().value();
144
145                                 @SuppressWarnings("unchecked")
146                                 Iterable<TitanVertex> vertecies = tGraph.query().has(name.getProperty(), value).has(GraphPropertyEnum.LABEL.getProperty(), label.getName()).vertices();
147
148                                 java.util.Iterator<TitanVertex> iterator = vertecies.iterator();
149                                 if (iterator.hasNext()) {
150                                         TitanVertex vertex = iterator.next();
151                                         GraphVertex graphVertex = createAndFill(vertex, parseFlag);
152
153                                         return Either.left(graphVertex);
154                                 }
155                                 if (logger.isDebugEnabled()) {
156                                         logger.debug("No vertex in graph for key = {}  and value = {}   label = {}" + name, value, label);
157                                 }
158                                 return Either.right(TitanOperationStatus.NOT_FOUND);
159                         } catch (Exception e) {
160                                 if (logger.isDebugEnabled()) {
161                                         logger.debug("Failed to get vertex in graph for key ={} and value = {}  label = {}", name, value, label);
162                                 }
163                                 return Either.right(TitanGraphClient.handleTitanException(e));
164                         }
165
166                 } else {
167                         if (logger.isDebugEnabled()) {
168                                 logger.debug("No vertex in graph for key ={} and value = {}  label = {} error :{}", name, value, label, graph.right().value());
169                         }
170                         return Either.right(graph.right().value());
171                 }
172         }
173
174         /**
175          * 
176          * @param id
177          * @return
178          */
179         public Either<GraphVertex, TitanOperationStatus> getVertexById(String id) {
180                 return getVertexById(id, JsonParseFlagEnum.ParseAll);
181         }
182
183         /**
184          * 
185          * @param id
186          * @param parseFlag
187          * @return
188          */
189         public Either<GraphVertex, TitanOperationStatus> getVertexById(String id, JsonParseFlagEnum parseFlag) {
190
191                 Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
192                 if (id == null) {
193                         if (logger.isDebugEnabled()) {
194                                 logger.debug("No vertex in graph for id = {} ", id);
195                         }
196                         return Either.right(TitanOperationStatus.NOT_FOUND);
197                 }
198                 if (graph.isLeft()) {
199                         try {
200                                 TitanGraph tGraph = graph.left().value();
201
202                                 @SuppressWarnings("unchecked")
203                                 Iterable<TitanVertex> vertecies = tGraph.query().has(GraphPropertyEnum.UNIQUE_ID.getProperty(), id).vertices();
204
205                                 java.util.Iterator<TitanVertex> iterator = vertecies.iterator();
206                                 if (iterator.hasNext()) {
207                                         TitanVertex vertex = iterator.next();
208                                         GraphVertex graphVertex = createAndFill(vertex, parseFlag);
209                                         return Either.left(graphVertex);
210                                 } else {
211                                         if (logger.isDebugEnabled()) {
212                                                 logger.debug("No vertex in graph for id = {}", id);
213                                         }
214                                         return Either.right(TitanOperationStatus.NOT_FOUND);
215                                 }
216                         } catch (Exception e) {
217                                 if (logger.isDebugEnabled()) {
218                                         logger.debug("Failed to get vertex in graph for id {} ", id);
219                                 }
220                                 return Either.right(TitanGraphClient.handleTitanException(e));
221                         }
222                 } else {
223                         if (logger.isDebugEnabled()) {
224                                 logger.debug("No vertex in graph for id {} error : {}", id, graph.right().value());
225                         }
226                         return Either.right(graph.right().value());
227                 }
228         }
229
230         private void setVertexProperties(TitanVertex vertex, GraphVertex graphVertex) throws IOException {
231
232                 if (graphVertex.getMetadataProperties() != null) {
233                         for (Map.Entry<GraphPropertyEnum, Object> entry : graphVertex.getMetadataProperties().entrySet()) {
234                                 if (entry.getValue() != null) {
235                                         vertex.property(entry.getKey().getProperty(), entry.getValue());
236                                 }
237                         }
238                 }
239                 vertex.property(GraphPropertyEnum.LABEL.getProperty(), graphVertex.getLabel().getName());
240
241                 Map<String, ? extends ToscaDataDefinition> json = graphVertex.getJson();
242                 if (json != null) {
243                         String jsonStr = JsonParserUtils.jsonToString(json);
244                         vertex.property(GraphPropertyEnum.JSON.getProperty(), jsonStr);
245
246                 }
247                 Map<String, Object> jsonMetadata = graphVertex.getMetadataJson();
248                 if (jsonMetadata != null) {
249                         String jsonMetadataStr = JsonParserUtils.jsonToString(jsonMetadata);
250                         vertex.property(GraphPropertyEnum.METADATA.getProperty(), jsonMetadataStr);
251                 }
252         }
253
254         public void setVertexProperties(Vertex vertex, Map<String, Object> properties) throws IOException {
255                 for (Map.Entry<String, Object> entry : properties.entrySet()) {
256                         if (entry.getValue() != null) {
257                                 vertex.property(entry.getKey(), entry.getValue());
258                         }
259                 }
260         }
261
262         private GraphVertex createAndFill(TitanVertex vertex, JsonParseFlagEnum parseFlag) {
263                 GraphVertex graphVertex = new GraphVertex();
264                 graphVertex.setVertex(vertex);
265                 parseVertexProperties(graphVertex, parseFlag);
266                 return graphVertex;
267         }
268
269         public void parseVertexProperties(GraphVertex graphVertex, JsonParseFlagEnum parseFlag ) {
270                 TitanVertex vertex = graphVertex.getVertex();
271                 Map<GraphPropertyEnum, Object> properties = getVertexProperties(vertex);
272                 VertexTypeEnum label = VertexTypeEnum.getByName((String) (properties.get(GraphPropertyEnum.LABEL)));
273                 for (Map.Entry<GraphPropertyEnum, Object> entry : properties.entrySet()) {
274                         GraphPropertyEnum key = entry.getKey();
275                         switch (key) {
276                         case UNIQUE_ID:
277                                 graphVertex.setUniqueId((String) entry.getValue());
278                                 break;
279                         case LABEL:
280                                 graphVertex.setLabel(VertexTypeEnum.getByName((String) entry.getValue()));
281                                 break;
282                         case COMPONENT_TYPE:
283                                 String type = (String) entry.getValue();
284                                 if (type != null) {
285                                         graphVertex.setType(ComponentTypeEnum.valueOf(type));
286                                 }
287                                 break;
288                         case JSON:
289                                 if (parseFlag == JsonParseFlagEnum.ParseAll || parseFlag == JsonParseFlagEnum.ParseJson) {
290                                         String json = (String) entry.getValue();
291                                         Map<String, ? extends ToscaDataDefinition> jsonObj = JsonParserUtils.parseToJson(json, label.getClassOfJson());
292                                         graphVertex.setJson(jsonObj);
293                                 }
294                                 break;
295                         case METADATA:
296                                 if (parseFlag == JsonParseFlagEnum.ParseAll || parseFlag == JsonParseFlagEnum.ParseMetadata) {
297                                         String json = (String) entry.getValue();
298                                         Map<String, Object> metadatObj = JsonParserUtils.parseToJson(json);
299                                         graphVertex.setMetadataJson(metadatObj);
300                                 }
301                                 break;
302                         default:
303                                 graphVertex.addMetadataProperty(key, entry.getValue());
304                                 break;
305                         }
306                 }
307         }
308
309         public TitanOperationStatus createEdge(GraphVertex from, GraphVertex to, EdgeLabelEnum label, Map<EdgePropertyEnum, Object> properties) {
310                 return createEdge(from.getVertex(), to.getVertex(), label, properties);
311         }
312
313         public TitanOperationStatus createEdge(Vertex from, Vertex to, EdgeLabelEnum label, Map<EdgePropertyEnum, Object> properties) {
314                 if (logger.isTraceEnabled()) {
315                         logger.trace("Try to connect {} with {} label {} properties {}", from.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), to.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), label, properties);
316                 }
317                 if (from == null || to == null) {
318                         logger.trace("No Titan vertex for id from {} or id to {}", from.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), to.property(GraphPropertyEnum.UNIQUE_ID.getProperty()));
319                         return TitanOperationStatus.NOT_FOUND;
320                 }
321                 Edge edge = from.addEdge(label.name(), to);
322                 setEdgeProperties(edge, properties);
323                 return TitanOperationStatus.OK;
324         }
325
326         public Map<GraphPropertyEnum, Object> getVertexProperties(Element element) {
327
328                 Map<GraphPropertyEnum, Object> result = new HashMap<GraphPropertyEnum, Object>();
329
330                 if (element != null && element.keys() != null && element.keys().size() > 0) {
331                         Map<String, Property> propertyMap = ElementHelper.propertyMap(element, element.keys().toArray(new String[element.keys().size()]));
332
333                         for (Entry<String, Property> entry : propertyMap.entrySet()) {
334                                 String key = entry.getKey();
335                                 Object value = entry.getValue().value();
336
337                                 GraphPropertyEnum valueOf = GraphPropertyEnum.getByProperty(key);
338                                 if (valueOf != null) {
339                                         result.put(valueOf, value);
340                                 }
341                         }
342                 }
343                 return result;
344         }
345
346         public Map<EdgePropertyEnum, Object> getEdgeProperties(Element element) {
347
348                 Map<EdgePropertyEnum, Object> result = new HashMap<EdgePropertyEnum, Object>();
349
350                 if (element != null && element.keys() != null && element.keys().size() > 0) {
351                         Map<String, Property> propertyMap = ElementHelper.propertyMap(element, element.keys().toArray(new String[element.keys().size()]));
352
353                         for (Entry<String, Property> entry : propertyMap.entrySet()) {
354                                 String key = entry.getKey();
355                                 Object value = entry.getValue().value();
356
357                                 EdgePropertyEnum valueOf = EdgePropertyEnum.getByProperty(key);
358                                 if (valueOf != null) {
359                                         result.put(valueOf, value);
360                                 }
361                         }
362                 }
363                 return result;
364         }
365
366         public void setEdgeProperties(Element element, Map<EdgePropertyEnum, Object> properties) {
367
368                 if (properties != null && !properties.isEmpty()) {
369
370                         Object[] propertyKeyValues = new Object[properties.size() * 2];
371                         int i = 0;
372                         for (Entry<EdgePropertyEnum, Object> entry : properties.entrySet()) {
373                                 propertyKeyValues[i++] = entry.getKey().getProperty();
374                                 propertyKeyValues[i++] = entry.getValue();
375                         }
376
377                         ElementHelper.attachProperties(element, propertyKeyValues);
378
379                 }
380
381         }
382
383         public Either<List<GraphVertex>, TitanOperationStatus> getByCriteria(VertexTypeEnum type, Map<GraphPropertyEnum, Object> props) {
384                 return getByCriteria(type, props, JsonParseFlagEnum.ParseAll);
385         }
386
387         public Either<List<GraphVertex>, TitanOperationStatus> getByCriteria(VertexTypeEnum type, Map<GraphPropertyEnum, Object> props, JsonParseFlagEnum parseFlag) {
388                 Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
389                 if (graph.isLeft()) {
390                         try {
391                                 TitanGraph tGraph = graph.left().value();
392
393                                 TitanGraphQuery<? extends TitanGraphQuery> query = tGraph.query();
394                                 if (type != null) {
395                                         query = query.has(GraphPropertyEnum.LABEL.getProperty(), type.getName());
396                                 }
397
398                                 if (props != null && !props.isEmpty()) {
399                                         for (Map.Entry<GraphPropertyEnum, Object> entry : props.entrySet()) {
400                                                 query = query.has(entry.getKey().getProperty(), entry.getValue());
401                                         }
402                                 }
403                                 Iterable<TitanVertex> vertices = query.vertices();
404                                 if (vertices == null) {
405                                         return Either.right(TitanOperationStatus.NOT_FOUND);
406                                 }
407
408                                 Iterator<TitanVertex> iterator = vertices.iterator();
409                                 List<GraphVertex> result = new ArrayList<GraphVertex>();
410
411                                 while (iterator.hasNext()) {
412                                         TitanVertex vertex = iterator.next();
413
414                                         Map<GraphPropertyEnum, Object> newProp = getVertexProperties(vertex);
415                                         GraphVertex graphVertex = createAndFill(vertex, parseFlag);
416
417                                         result.add(graphVertex);
418                                 }
419                                 if (logger.isDebugEnabled()) {
420                                         logger.debug("Number of fetced nodes in graph for criteria : from type = {} and properties = {} is {}", type, props, result.size());
421                                 }
422                                 if (result.size() == 0) {
423                                         return Either.right(TitanOperationStatus.NOT_FOUND);
424                                 }
425
426                                 return Either.left(result);
427                         } catch (Exception e) {
428                                 if (logger.isDebugEnabled()) {
429                                         logger.debug("Failed  get by  criteria for type = {} and properties = {}", type, props, e);
430                                 }
431                                 return Either.right(TitanGraphClient.handleTitanException(e));
432                         }
433
434                 } else {
435                         if (logger.isDebugEnabled()) {
436                                 logger.debug("Failed  get by  criteria for type ={} and properties = {} error : {}", type, props, graph.right().value());
437                         }
438                         return Either.right(graph.right().value());
439                 }
440         }
441         public Either<List<GraphVertex>, TitanOperationStatus> getByCriteria(VertexTypeEnum type, Map<GraphPropertyEnum, Object> props, Map<GraphPropertyEnum, Object> hasNotProps, JsonParseFlagEnum parseFlag) {
442                 Either<TitanGraph, TitanOperationStatus> graph = titanClient.getGraph();
443                 if (graph.isLeft()) {
444                         try {
445                                 TitanGraph tGraph = graph.left().value();
446
447                                 TitanGraphQuery<? extends TitanGraphQuery> query = tGraph.query();
448                                 if (type != null) {
449                                         query = query.has(GraphPropertyEnum.LABEL.getProperty(), type.getName());
450                                 }
451
452                                 if (props != null && !props.isEmpty()) {
453                                         for (Map.Entry<GraphPropertyEnum, Object> entry : props.entrySet()) {
454                                                 query = query.has(entry.getKey().getProperty(), entry.getValue());
455                                         }
456                                 }
457                                 if (hasNotProps != null && !hasNotProps.isEmpty()) {
458                                         for (Map.Entry<GraphPropertyEnum, Object> entry : hasNotProps.entrySet()) {
459                                                 if(entry.getValue() instanceof List){
460                                                         buildMultipleNegateQueryFromList(entry, query);
461                                                 }else{
462                                                         query = query.hasNot(entry.getKey().getProperty(), entry.getValue());
463                                                 }
464                                         }
465                                 }
466                                 Iterable<TitanVertex> vertices = query.vertices();
467                                 if (vertices == null) {
468                                         return Either.right(TitanOperationStatus.NOT_FOUND);
469                                 }
470
471                                 Iterator<TitanVertex> iterator = vertices.iterator();
472                                 List<GraphVertex> result = new ArrayList<GraphVertex>();
473
474                                 while (iterator.hasNext()) {
475                                         TitanVertex vertex = iterator.next();
476
477                                         Map<GraphPropertyEnum, Object> newProp = getVertexProperties(vertex);
478                                         GraphVertex graphVertex = createAndFill(vertex, parseFlag);
479
480                                         result.add(graphVertex);
481                                 }
482                                 if (logger.isDebugEnabled()) {
483                                         logger.debug("Number of fetced nodes in graph for criteria : from type = {} and properties = {} is {}", type, props, result.size());
484                                 }
485                                 if (result.size() == 0) {
486                                         return Either.right(TitanOperationStatus.NOT_FOUND);
487                                 }
488
489                                 return Either.left(result);
490                         } catch (Exception e) {
491                                 if (logger.isDebugEnabled()) {
492                                         logger.debug("Failed  get by  criteria for type = {} and properties = {}", type, props, e);
493                                 }
494                                 return Either.right(TitanGraphClient.handleTitanException(e));
495                         }
496
497                 } else {
498                         if (logger.isDebugEnabled()) {
499                                 logger.debug("Failed  get by  criteria for type ={} and properties = {} error : {}", type, props, graph.right().value());
500                         }
501                         return Either.right(graph.right().value());
502                 }
503         }
504         
505         
506         
507         private void buildMultipleNegateQueryFromList(Map.Entry<GraphPropertyEnum, Object> entry, TitanGraphQuery query){
508                 List<Object> negateList = (List<Object>) entry.getValue();
509                 for (Object listItem : negateList) {
510                         query.hasNot(entry.getKey().getProperty(), listItem);
511                 }
512         }
513         
514         
515         /**
516          * 
517          * @param parentVertex
518          * @param edgeLabel
519          * @param parseFlag
520          * @return
521          */
522         public Either<GraphVertex, TitanOperationStatus> getChildVertex(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
523                 Either<List<GraphVertex>, TitanOperationStatus> childrenVertecies = getChildrenVertecies(parentVertex, edgeLabel, parseFlag);
524                 if (childrenVertecies.isRight()) {
525                         return Either.right(childrenVertecies.right().value());
526                 }
527                 return Either.left(childrenVertecies.left().value().get(0));
528         }
529
530         public Either<GraphVertex, TitanOperationStatus> getParentVertex(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
531                 Either<List<GraphVertex>, TitanOperationStatus> childrenVertecies = getParentVertecies(parentVertex, edgeLabel, parseFlag);
532                 if (childrenVertecies.isRight()) {
533                         return Either.right(childrenVertecies.right().value());
534                 }
535                 return Either.left(childrenVertecies.left().value().get(0));
536         }
537
538         /**
539          * 
540          * @param parentVertex
541          * @param edgeLabel
542          * @param parseFlag
543          * @return
544          */
545         public Either<List<GraphVertex>, TitanOperationStatus> getChildrenVertecies(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
546                 return getAdjacentVerticies(parentVertex, edgeLabel, parseFlag, Direction.OUT);
547         }
548
549         public Either<List<GraphVertex>, TitanOperationStatus> getParentVertecies(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag) {
550                 return getAdjacentVerticies(parentVertex, edgeLabel, parseFlag, Direction.IN);
551         }
552
553         private Either<List<GraphVertex>, TitanOperationStatus> getAdjacentVerticies(GraphVertex parentVertex, EdgeLabelEnum edgeLabel, JsonParseFlagEnum parseFlag, Direction direction) {
554                 List<GraphVertex> list = new ArrayList<GraphVertex>();
555
556                 try {
557                         Either<TitanGraph, TitanOperationStatus> graphRes = titanClient.getGraph();
558                         if (graphRes.isRight()) {
559                                 logger.error("Failed to retrieve graph. status is {}", graphRes);
560                                 return Either.right(graphRes.right().value());
561                         }
562                         Iterator<Edge> edgesCreatorIterator = parentVertex.getVertex().edges(direction, edgeLabel.name());
563                         if (edgesCreatorIterator != null) {
564                                 while (edgesCreatorIterator.hasNext()) {
565                                         Edge edge = edgesCreatorIterator.next();
566                                         TitanVertex vertex;
567                                         if (direction == Direction.IN) {
568                                                 vertex = (TitanVertex) edge.outVertex();
569                                         } else {
570                                                 vertex = (TitanVertex) edge.inVertex();
571                                         }
572                                         GraphVertex graphVertex = createAndFill(vertex, parseFlag);
573
574                                         list.add(graphVertex);
575                                 }
576                         }
577                         if (true == list.isEmpty()) {
578                                 return Either.right(TitanOperationStatus.NOT_FOUND);
579                         }
580                 } catch (Exception e) {
581                         logger.error("Failed to perform graph operation ", e);
582                         Either.right(TitanGraphClient.handleTitanException(e));
583                 }
584
585                 return Either.left(list);
586         }
587
588         /**
589          * Searches Edge by received label and criteria
590          * 
591          * @param vertex
592          * @param label
593          * @param properties
594          * @return found edge or TitanOperationStatus
595          */
596         public Either<Edge, TitanOperationStatus> getBelongingEdgeByCriteria(GraphVertex vertex, EdgeLabelEnum label, Map<GraphPropertyEnum, Object> properties) {
597
598                 Either<Edge, TitanOperationStatus> result = null;
599                 Edge matchingEdge = null;
600                 String notFoundMsg = "No edges in graph for criteria";
601                 try {
602                         TitanVertexQuery<?> query = vertex.getVertex().query().labels(label.name());
603
604                         if (properties != null && !properties.isEmpty()) {
605                                 for (Map.Entry<GraphPropertyEnum, Object> entry : properties.entrySet()) {
606                                         query = query.has(entry.getKey().getProperty(), entry.getValue());
607                                 }
608                         }
609
610                         Iterable<TitanEdge> edges = query.edges();
611                         if (edges == null) {
612                                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, notFoundMsg);
613                                 result = Either.right(TitanOperationStatus.NOT_FOUND);
614                         } else {
615                                 Iterator<TitanEdge> eIter = edges.iterator();
616                                 if (eIter.hasNext()) {
617                                         matchingEdge = eIter.next();
618                                 } else {
619                                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, notFoundMsg);
620                                         result = Either.right(TitanOperationStatus.NOT_FOUND);
621                                 }
622                         }
623                         if (result == null) {
624                                 result = Either.left(matchingEdge);
625                         }
626                 } catch (Exception e) {
627                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during getting edge by criteria for component with id {}. {}", vertex.getUniqueId(), e);
628                         return Either.right(TitanGraphClient.handleTitanException(e));
629                 }
630                 return result;
631         }
632
633         /**
634          * Deletes Edge by received label and criteria
635          * 
636          * @param vertex
637          * @param label
638          * @param properties
639          * @return
640          */
641         public Either<Edge, TitanOperationStatus> deleteBelongingEdgeByCriteria(GraphVertex vertex, EdgeLabelEnum label, Map<GraphPropertyEnum, Object> properties) {
642                 Either<Edge, TitanOperationStatus> result = null;
643                 try {
644                         result = getBelongingEdgeByCriteria(vertex, label, properties);
645                         if (result.isLeft()) {
646                                 Edge edge = result.left().value();
647                                 CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to delete an edge with the label {} belonging to the vertex {} ", label.name(), vertex.getUniqueId());
648                                 edge.remove();
649                                 result = Either.left(edge);
650                         } else {
651                                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to find an edge with the label {} belonging to the vertex {} ", label.name(), vertex.getUniqueId());
652                         }
653                 } catch (Exception e) {
654                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleting an edge by criteria for the component with id {}. {}", vertex.getUniqueId(), e);
655                         return Either.right(TitanGraphClient.handleTitanException(e));
656                 }
657                 return result;
658         }
659
660         @SuppressWarnings("unchecked")
661         /**
662          * Deletes an edge between vertices fromVertex and toVertex according to received label
663          * 
664          * @param fromVertex
665          * @param toVertex
666          * @param label
667          * @return
668          */
669         public Either<Edge, TitanOperationStatus> deleteEdge(GraphVertex fromVertex, GraphVertex toVertex, EdgeLabelEnum label) {
670                 Either<Edge, TitanOperationStatus> result = null;
671                 try {
672                         Iterable<TitanEdge> edges = fromVertex.getVertex().query().labels(label.name()).edges();
673                         Iterator<TitanEdge> eIter = edges.iterator();
674                         while (eIter.hasNext()) {
675                                 Edge edge = eIter.next();
676                                 String currVertexUniqueId = edge.inVertex().value(GraphPropertyEnum.UNIQUE_ID.getProperty());
677                                 if (currVertexUniqueId != null && currVertexUniqueId.equals(toVertex.getUniqueId())) {
678                                         CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to delete an edge with the label {} between vertices {} and {}. ", label.name(), fromVertex.getUniqueId(), toVertex.getUniqueId());
679                                         edge.remove();
680                                         result = Either.left(edge);
681                                         break;
682                                 }
683                         }
684                         if (result == null) {
685                                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to delete an edge with the label {} between vertices {} and {}. ", label.name(), fromVertex.getUniqueId(), toVertex.getUniqueId());
686                                 result = Either.right(TitanOperationStatus.NOT_FOUND);
687                         }
688                 } catch (Exception e) {
689                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleting an edge with the label {} between vertices {} and {}. {}", label.name(), fromVertex.getUniqueId(), toVertex.getUniqueId(), e);
690                         return Either.right(TitanGraphClient.handleTitanException(e));
691                 }
692                 return result;
693         }
694
695         public TitanOperationStatus deleteEdgeByDirection(GraphVertex fromVertex, Direction direction, EdgeLabelEnum label) {
696                 try {
697                         Iterator<Edge> edges = fromVertex.getVertex().edges(direction, label.name());
698
699                         while (edges.hasNext()) {
700                                 Edge edge = edges.next();
701                                 edge.remove();
702                         }
703                 } catch (Exception e) {
704                         logger.debug("Failed to remove from vertex {} edges {} by direction {} ", fromVertex.getUniqueId(), label, direction, e);
705                         return TitanGraphClient.handleTitanException(e);
706                 }
707                 return TitanOperationStatus.OK;
708         }
709
710         /**
711          * Updates vertex properties. Note that graphVertex argument should contain updated data
712          * 
713          * @param graphVertex
714          * @return
715          */
716         public Either<GraphVertex, TitanOperationStatus> updateVertex(GraphVertex graphVertex) {
717                 CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to update metadata of vertex with uniqueId {}. ", graphVertex.getUniqueId());
718                 try {
719                         graphVertex.updateMetadataJsonWithCurrentMetadataProperties();
720                         setVertexProperties(graphVertex.getVertex(), graphVertex);
721
722                 } catch (Exception e) {
723                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to update metadata of vertex with uniqueId {}. ", graphVertex.getUniqueId(), e);
724                         return Either.right(TitanGraphClient.handleTitanException(e));
725                 }
726                 return Either.left(graphVertex);
727         }
728
729         /**
730          * Fetches vertices by uniqueId according to received parse flag
731          * 
732          * @param verticesToGet
733          * @return
734          */
735         public Either<Map<String, GraphVertex>, TitanOperationStatus> getVerticesByUniqueIdAndParseFlag(Map<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> verticesToGet) {
736
737                 Either<Map<String, GraphVertex>, TitanOperationStatus> result = null;
738                 Map<String, GraphVertex> vertices = new HashMap<>();
739                 TitanOperationStatus titatStatus;
740                 Either<GraphVertex, TitanOperationStatus> getVertexRes = null;
741                 for (Map.Entry<String, ImmutablePair<GraphPropertyEnum, JsonParseFlagEnum>> entry : verticesToGet.entrySet()) {
742                         if (entry.getValue().getKey() == GraphPropertyEnum.UNIQUE_ID) {
743                                 getVertexRes = getVertexById(entry.getKey(), entry.getValue().getValue());
744                         } else if (entry.getValue().getKey() == GraphPropertyEnum.USERID) {
745                                 getVertexRes = getVertexByPropertyAndLabel(entry.getValue().getKey(), entry.getKey(), VertexTypeEnum.USER, entry.getValue().getValue());
746                         }
747                         if (getVertexRes == null) {
748                                 titatStatus = TitanOperationStatus.ILLEGAL_ARGUMENT;
749                                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Invalid vertex type label {} has been received. ", entry.getValue().getKey(), titatStatus);
750                                 result = Either.right(titatStatus);
751                         }
752                         if (getVertexRes.isRight()) {
753                                 titatStatus = getVertexRes.right().value();
754                                 CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to get vertex by id {} . Status is {}. ", entry.getKey(), titatStatus);
755                                 result = Either.right(titatStatus);
756                                 break;
757                         } else {
758                                 vertices.put(entry.getKey(), getVertexRes.left().value());
759                         }
760                 }
761                 if (result == null) {
762                         result = Either.left(vertices);
763                 }
764                 return result;
765         }
766
767         /**
768          * Creates edge between "from" and "to" vertices with specified label and properties extracted from received edge
769          * 
770          * @param from
771          * @param to
772          * @param label
773          * @param edgeToCopy
774          * @return
775          */
776         public TitanOperationStatus createEdge(Vertex from, Vertex to, EdgeLabelEnum label, Edge edgeToCopy) {
777                 return createEdge(from, to, label, getEdgeProperties(edgeToCopy));
778         }
779
780         public TitanOperationStatus replaceEdgeLabel(Vertex fromVertex, Vertex toVertex, Edge prevEdge, EdgeLabelEnum prevLabel, EdgeLabelEnum newLabel) {
781
782                 CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Going to replace edge with label {} to {} between vertices {} and {}", prevLabel, newLabel, fromVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()),
783                                 toVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()));
784                 TitanOperationStatus result = createEdge(fromVertex, toVertex, newLabel, prevEdge);
785                 if (result == TitanOperationStatus.OK) {
786                         prevEdge.remove();
787                 }
788                 return result;
789         }
790
791         /**
792          * Replaces previous label of edge with new label
793          * 
794          * @param fromVertex
795          * @param toVertex
796          * @param prevLabel
797          * @param newLabel
798          * @return
799          */
800         public TitanOperationStatus replaceEdgeLabel(Vertex fromVertex, Vertex toVertex, EdgeLabelEnum prevLabel, EdgeLabelEnum newLabel) {
801
802                 TitanOperationStatus result = null;
803                 Iterator<Edge> prevEdgeIter = toVertex.edges(Direction.IN, prevLabel.name());
804                 if (prevEdgeIter == null || !prevEdgeIter.hasNext()) {
805                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Failed to replace edge with label {} to {} between vertices {} and {}", prevLabel, newLabel, fromVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()),
806                                         toVertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()));
807                         result = TitanOperationStatus.NOT_FOUND;
808                 }
809                 if (result == null) {
810                         result = replaceEdgeLabel(fromVertex, toVertex, prevEdgeIter.next(), prevLabel, newLabel);
811                 }
812                 return result;
813         }
814
815         /**
816          * Updates metadata properties of vertex on graph. Json metadata property of the vertex will be updated with received properties too.
817          * 
818          * 
819          * @param vertex
820          * @param properties
821          * @return
822          */
823         public TitanOperationStatus updateVertexMetadataPropertiesWithJson(Vertex vertex, Map<GraphPropertyEnum, Object> properties) {
824                 try {
825                         if (!MapUtils.isEmpty(properties)) {
826                                 String jsonMetadataStr = (String) vertex.property(GraphPropertyEnum.METADATA.getProperty()).value();
827                                 Map<String, Object> jsonMetadataMap = JsonParserUtils.parseToJson(jsonMetadataStr);
828                                 for (Map.Entry<GraphPropertyEnum, Object> property : properties.entrySet()) {
829                                         vertex.property(property.getKey().getProperty(), property.getValue());
830                                         jsonMetadataMap.put(property.getKey().getProperty(), property.getValue());
831                                 }
832                                 vertex.property(GraphPropertyEnum.METADATA.getProperty(), JsonParserUtils.jsonToString(jsonMetadataMap));
833                         }
834                 } catch (Exception e) {
835                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during update vertex metadata properties with json{}. {}", vertex.property(GraphPropertyEnum.UNIQUE_ID.getProperty()), e.getMessage());
836                         return TitanGraphClient.handleTitanException(e);
837                 }
838                 return TitanOperationStatus.OK;
839         }
840
841         public TitanOperationStatus disassociateAndDeleteLast(GraphVertex vertex, Direction direction, EdgeLabelEnum label) {
842                 try {
843                         Iterator<Edge> edges = vertex.getVertex().edges(direction, label.name());
844
845                         while (edges.hasNext()) {
846                                 Edge edge = edges.next();
847                                 Vertex secondVertex;
848                                 Direction reverseDirection;
849                                 if (direction == Direction.IN) {
850                                         secondVertex = edge.outVertex();
851                                         reverseDirection = Direction.OUT;
852                                 } else {
853                                         secondVertex = edge.inVertex();
854                                         reverseDirection = Direction.IN;
855                                 }
856                                 edge.remove();
857                                 CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "Edge  {} with direction {} was removed from {}", label.name(), direction, vertex.getVertex());
858
859                                 Iterator<Edge> restOfEdges = secondVertex.edges(reverseDirection, label.name());
860                                 if (restOfEdges.hasNext() == false) {
861                                         secondVertex.remove();
862                                         CommonUtility.addRecordToLog(logger, LogLevelEnum.TRACE, "This was last edge . Vertex  {} was removed ", vertex.getUniqueId());
863                                 }
864                         }
865                 } catch (Exception e) {
866                         CommonUtility.addRecordToLog(logger, LogLevelEnum.DEBUG, "Exception occured during deleting an edge with the label {} direction {} from vertex {}. {}", label.name(), direction, vertex.getUniqueId(), e);
867                         return TitanGraphClient.handleTitanException(e);
868                 }
869                 return TitanOperationStatus.OK;
870         }
871
872         public Object getProperty(TitanVertex vertex, String key) {
873                 PropertyKey propertyKey = titanClient.getGraph().left().value().getPropertyKey(key);
874                 Object value = vertex.valueOrNull(propertyKey);
875                 return value;
876         }
877
878         public Object getProperty(Edge edge, EdgePropertyEnum key) {
879                 Object value = null;
880                 try {
881                         Property<Object> property = edge.property(key.getProperty());
882                         if (property != null) {
883                                 return property.orElse(null);
884                         }
885                 } catch (Exception e) {
886
887                 }
888                 return value;
889         }
890         /** 
891          * 
892          * @param vertexA
893          * @param vertexB
894          * @param label
895          * @param direction
896          * @return
897          */
898         public TitanOperationStatus moveEdge(GraphVertex vertexA, GraphVertex vertexB, EdgeLabelEnum label, Direction direction) {
899                  TitanOperationStatus result = deleteEdgeByDirection(vertexA, direction, label);
900                  if ( result != TitanOperationStatus.OK ){
901                                 logger.error("Failed to diassociate {} from element {}. error {} ", label, vertexA.getUniqueId(), result);
902                                 return result;
903                  }
904                  TitanOperationStatus createRelation;
905                  if (direction == Direction.IN ){
906                          createRelation = createEdge(vertexB, vertexA, label, null);
907                  }else{
908                          createRelation = createEdge(vertexA, vertexB, label, null);
909                  }
910                 if (createRelation != TitanOperationStatus.OK) {
911                         return createRelation;
912                 }
913                 return TitanOperationStatus.OK;
914         }
915
916         public Either<Edge, TitanOperationStatus> getBelongingEdgeByCriteria(String parentId, EdgeLabelEnum label, Map<GraphPropertyEnum, Object> properties) {
917                 Either<GraphVertex, TitanOperationStatus> getVertexRes = getVertexById(parentId, JsonParseFlagEnum.NoParse);
918                 if(getVertexRes.isRight()){
919                         return Either.right(getVertexRes.right().value());
920                 }
921                 return getBelongingEdgeByCriteria(getVertexRes.left().value(), label, properties);
922         }
923 }