8382af5e8b37d2ab41e720653d675181bb2fc094
[sdc.git] / catalog-dao / src / main / java / org / openecomp / sdc / be / dao / janusgraph / JanusGraphGenericDao.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 package org.openecomp.sdc.be.dao.janusgraph;
21
22 import fj.data.Either;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.function.Predicate;
30 import java.util.stream.Collectors;
31 import java.util.stream.StreamSupport;
32 import javax.validation.constraints.NotNull;
33 import org.apache.commons.collections.CollectionUtils;
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.commons.lang3.tuple.ImmutablePair;
36 import org.apache.commons.lang3.tuple.ImmutableTriple;
37 import org.apache.tinkerpop.gremlin.structure.Direction;
38 import org.apache.tinkerpop.gremlin.structure.Edge;
39 import org.apache.tinkerpop.gremlin.structure.Element;
40 import org.apache.tinkerpop.gremlin.structure.Property;
41 import org.apache.tinkerpop.gremlin.structure.Vertex;
42 import org.apache.tinkerpop.gremlin.structure.util.ElementHelper;
43 import org.janusgraph.core.JanusGraph;
44 import org.janusgraph.core.JanusGraphEdge;
45 import org.janusgraph.core.JanusGraphQuery;
46 import org.janusgraph.core.JanusGraphVertex;
47 import org.janusgraph.core.JanusGraphVertexQuery;
48 import org.janusgraph.core.PropertyKey;
49 import org.janusgraph.graphdb.query.JanusGraphPredicate;
50 import org.openecomp.sdc.be.config.ConfigurationManager;
51 import org.openecomp.sdc.be.dao.api.exception.JanusGraphException;
52 import org.openecomp.sdc.be.dao.graph.GraphElementFactory;
53 import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge;
54 import org.openecomp.sdc.be.dao.graph.datatype.GraphElementTypeEnum;
55 import org.openecomp.sdc.be.dao.graph.datatype.GraphNode;
56 import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation;
57 import org.openecomp.sdc.be.dao.graph.datatype.RelationEndPoint;
58 import org.openecomp.sdc.be.dao.jsongraph.types.EdgeLabelEnum;
59 import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels;
60 import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary;
61 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
62 import org.openecomp.sdc.be.resources.data.GraphNodeLock;
63 import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode;
64 import org.openecomp.sdc.common.log.wrappers.Logger;
65 import org.springframework.beans.factory.annotation.Qualifier;
66
67 public class JanusGraphGenericDao {
68
69     private static final String LOCK_NODE_PREFIX = "lock_";
70     private static Logger log = Logger.getLogger(JanusGraphGenericDao.class.getName());
71     private JanusGraphClient janusGraphClient;
72
73     public JanusGraphGenericDao(@Qualifier("janusgraph-client") JanusGraphClient janusGraphClient) {
74         this.janusGraphClient = janusGraphClient;
75         log.info("** JanusGraphGenericDao created");
76     }
77
78     public JanusGraphOperationStatus commit() {
79         log.debug("doing commit.");
80         return janusGraphClient.commit();
81     }
82
83     public JanusGraphOperationStatus rollback() {
84         log.error("Going to execute rollback on graph.");
85         return janusGraphClient.rollback();
86     }
87
88     public <T, TStatus> void handleTransactionCommitRollback(boolean inTransaction, Either<T, TStatus> result) {
89         if (!inTransaction) {
90             if (result == null || result.isRight()) {
91                 rollback();
92             } else {
93                 commit();
94             }
95         }
96     }
97
98     public Either<JanusGraph, JanusGraphOperationStatus> getGraph() {
99         return janusGraphClient.getGraph();
100     }
101
102     // For healthCheck
103     public boolean isGraphOpen() {
104         return janusGraphClient.getHealth();
105     }
106
107     /**
108      * @param node
109      * @param clazz
110      * @return
111      */
112     public <T extends GraphNode> Either<T, JanusGraphOperationStatus> createNode(T node, Class<T> clazz) {
113         log.debug("try to create node for ID [{}]", node.getKeyValueIdForLog());
114         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
115         if (graph.isLeft()) {
116             T newNode;
117             try {
118                 JanusGraph tGraph = graph.left().value();
119                 Vertex vertex = tGraph.addVertex();
120                 vertex.property(GraphPropertiesDictionary.LABEL.getProperty(), node.getLabel());
121                 Map<String, Object> properties = node.toGraphMap();
122                 if (properties != null) {
123                     setProperties(vertex, properties);
124                 }
125                 Map<String, Object> newProps = getProperties(vertex);
126                 newNode = GraphElementFactory.createElement(node.getLabel(), GraphElementTypeEnum.Node, newProps, clazz);
127                 log.debug("created node for props : {}", newProps);
128                 log.debug("Node was created for ID [{}]", node.getKeyValueIdForLog());
129                 return Either.left(newNode);
130             } catch (Exception e) {
131                 log.debug("Failed to create Node for ID [{}]", node.getKeyValueId(), e);
132                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
133             }
134         } else {
135             log.debug("Failed to create Node for ID [{}]  {}", node.getKeyValueIdForLog(), graph.right().value());
136             return Either.right(graph.right().value());
137         }
138     }
139
140     public Either<JanusGraphVertex, JanusGraphOperationStatus> createNode(GraphNode node) {
141         log.debug("try to create node for ID [{}]", node.getKeyValueId());
142         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
143         if (graph.isLeft()) {
144             try {
145                 JanusGraph tGraph = graph.left().value();
146                 JanusGraphVertex vertex = tGraph.addVertex();
147                 vertex.property(GraphPropertiesDictionary.LABEL.getProperty(), node.getLabel());
148                 Map<String, Object> properties = node.toGraphMap();
149                 if (properties != null) {
150                     setProperties(vertex, properties);
151                 }
152                 log.debug("Node was created for ID [{}]", node.getKeyValueId());
153                 return Either.left(vertex);
154             } catch (Exception e) {
155                 log.debug("Failed to create Node for ID [{}]", node.getKeyValueId(), e);
156                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
157             }
158         } else {
159             log.debug("Failed to create Node for ID [{}]  {}", node.getKeyValueId(), graph.right().value());
160             return Either.right(graph.right().value());
161         }
162     }
163
164     /**
165      * @param relation
166      * @return
167      */
168     public Either<GraphRelation, JanusGraphOperationStatus> createRelation(GraphRelation relation) {
169         log.debug("try to create relation from [{}] to [{}] ", relation.getFrom(), relation.getTo());
170         RelationEndPoint from = relation.getFrom();
171         RelationEndPoint to = relation.getTo();
172         ImmutablePair<String, Object> fromKeyId = new ImmutablePair<>(from.getIdName(), from.getIdValue());
173         ImmutablePair<String, Object> toKeyId = new ImmutablePair<>(to.getIdName(), to.getIdValue());
174         return createEdge(relation.getType(), fromKeyId, toKeyId, from.getLabel().getName(), to.getLabel().getName(), relation.toGraphMap());
175     }
176
177     private Either<GraphRelation, JanusGraphOperationStatus> createEdge(String type, ImmutablePair<String, Object> from,
178                                                                         ImmutablePair<String, Object> to, String fromLabel, String toLabel,
179                                                                         Map<String, Object> properties) {
180         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
181         if (graph.isLeft()) {
182             try {
183                 Either<Vertex, JanusGraphOperationStatus> fromV = getVertexByPropertyAndLabel(from.getKey(), from.getValue(), fromLabel);
184                 if (fromV.isRight()) {
185                     JanusGraphOperationStatus error = fromV.right().value();
186                     if (JanusGraphOperationStatus.NOT_FOUND.equals(error)) {
187                         return Either.right(JanusGraphOperationStatus.INVALID_ID);
188                     } else {
189                         return Either.right(error);
190                     }
191                 }
192                 Either<Vertex, JanusGraphOperationStatus> toV = getVertexByPropertyAndLabel(to.getKey(), to.getValue(), toLabel);
193                 if (toV.isRight()) {
194                     JanusGraphOperationStatus error = toV.right().value();
195                     if (JanusGraphOperationStatus.NOT_FOUND.equals(error)) {
196                         return Either.right(JanusGraphOperationStatus.INVALID_ID);
197                     } else {
198                         return Either.right(error);
199                     }
200                 }
201                 Vertex fromVertex = fromV.left().value();
202                 Vertex toVertex = toV.left().value();
203                 Edge edge = fromVertex.addEdge(type, toVertex);
204                 if (properties != null) {
205                     setProperties(edge, properties);
206                 }
207                 Vertex vertexOut = edge.outVertex();
208                 Vertex vertexIn = edge.inVertex();
209                 GraphNode nodeOut = GraphElementFactory
210                     .createElement(fromLabel, GraphElementTypeEnum.Node, getProperties(vertexOut), GraphNode.class);
211                 GraphNode nodeIn = GraphElementFactory.createElement(toLabel, GraphElementTypeEnum.Node, getProperties(vertexIn), GraphNode.class);
212                 GraphRelation newRelation = GraphElementFactory.createRelation(edge.label(), getProperties(edge), nodeOut, nodeIn);
213                 return Either.left(newRelation);
214             } catch (Exception e) {
215                 log.debug("Failed to create edge from [{}] to [{}]", from, to, e);
216                 return Either.right(janusGraphClient.handleJanusGraphException(e));
217             }
218         } else {
219             log.debug("Failed to create edge from [{}] to [{}]   {}", from, to, graph.right().value());
220             return Either.right(graph.right().value());
221         }
222     }
223
224     public JanusGraphOperationStatus createEdge(Vertex vertexOut, Vertex vertexIn, GraphEdgeLabels type, Map<String, Object> properties) {
225         try {
226             Edge edge = addEdge(vertexOut, vertexIn, type, properties);
227         } catch (Exception e) {
228             log.debug("Failed to create edge from [{}] to [{}]", vertexOut, vertexIn, e);
229             return janusGraphClient.handleJanusGraphException(e);
230         }
231         return JanusGraphOperationStatus.OK;
232     }
233
234     private Edge addEdge(Vertex vertexOut, Vertex vertexIn, GraphEdgeLabels type, Map<String, Object> properties) {
235         Edge edge = vertexOut.addEdge(type.getProperty(), vertexIn);
236         if (properties != null) {
237             setProperties(edge, properties);
238         }
239         return edge;
240     }
241
242     /**
243      * creates an identical edge in the graph
244      *
245      * @param edge
246      * @return the copy operation status
247      */
248     public Either<Edge, JanusGraphOperationStatus> copyEdge(Vertex out, Vertex in, Edge edge) {
249         GraphEdgeLabels byName = GraphEdgeLabels.getByName(edge.label());
250         return this.saveEdge(out, in, byName, edgePropertiesToMap(edge));
251     }
252
253     private <V> Map<String, Object> edgePropertiesToMap(Edge edge) {
254         Iterable<Property<Object>> propertiesIterable = edge::properties;
255         return StreamSupport.stream(propertiesIterable.spliterator(), false).collect(Collectors.toMap(Property::key, Property::value));
256     }
257
258     public Either<Edge, JanusGraphOperationStatus> saveEdge(Vertex vertexOut, Vertex vertexIn, GraphEdgeLabels type, Map<String, Object> properties) {
259         try {
260             Edge edge = addEdge(vertexOut, vertexIn, type, properties);
261             return Either.left(edge);
262         } catch (Exception e) {
263             log.debug("Failed to create edge from [{}] to [{}]", vertexOut, vertexIn, e);
264             return Either.right(janusGraphClient.handleJanusGraphException(e));
265         }
266     }
267
268     public JanusGraphOperationStatus createEdge(JanusGraphVertex vertexOut, GraphNode to, GraphEdgeLabels type, Map<String, Object> properties) {
269         JanusGraphVertex vertexIn;
270         Either<Vertex, JanusGraphOperationStatus> toV = getVertexByPropertyAndLabel(to.getUniqueIdKey(), to.getUniqueId(), to.getLabel());
271         if (toV.isRight()) {
272             JanusGraphOperationStatus error = toV.right().value();
273             if (JanusGraphOperationStatus.NOT_FOUND.equals(error)) {
274                 return JanusGraphOperationStatus.INVALID_ID;
275             } else {
276                 return error;
277             }
278         }
279         vertexIn = (JanusGraphVertex) toV.left().value();
280         return createEdge(vertexOut, vertexIn, type, properties);
281     }
282
283     /**
284      * @param from
285      * @param to
286      * @param label
287      * @param properties
288      * @return
289      */
290     public Either<GraphRelation, JanusGraphOperationStatus> createRelation(GraphNode from, GraphNode to, GraphEdgeLabels label,
291                                                                            Map<String, Object> properties) {
292         log.debug("try to create relation from [{}] to [{}]", from.getKeyValueId(), to.getKeyValueId());
293         return createEdge(label.getProperty(), from.getKeyValueId(), to.getKeyValueId(), from.getLabel(), to.getLabel(), properties);
294     }
295
296     public Either<GraphRelation, JanusGraphOperationStatus> replaceRelationLabel(GraphNode from, GraphNode to, GraphEdgeLabels label,
297                                                                                  GraphEdgeLabels newLabel) {
298         log.debug("try to replace relation {} to {} from [{}] to [{}]", label.name(), newLabel.name(), from.getKeyValueId(), to.getKeyValueId());
299         Either<GraphRelation, JanusGraphOperationStatus> getRelationResult = getRelation(from, to, label);
300         if (getRelationResult.isRight()) {
301             return getRelationResult;
302         }
303         GraphRelation origRelation = getRelationResult.left().value();
304         Either<GraphRelation, JanusGraphOperationStatus> createRelationResult = createRelation(from, to, newLabel, origRelation.toGraphMap());
305         if (createRelationResult.isRight()) {
306             return createRelationResult;
307         }
308         Either<GraphRelation, JanusGraphOperationStatus> deleteRelationResult = deleteRelation(origRelation);
309         if (deleteRelationResult.isRight()) {
310             return deleteRelationResult;
311         }
312         return Either.left(createRelationResult.left().value());
313     }
314
315     /**
316      * @param keyName
317      * @param keyValue
318      * @param clazz
319      * @return
320      */
321     public <T extends GraphNode> Either<T, JanusGraphOperationStatus> getNode(String keyName, Object keyValue, Class<T> clazz) {
322       log.debug("Try to get node for key [{}] with value [{}] ", keyName, keyValue);
323       Either<JanusGraphVertex, JanusGraphOperationStatus> vertexByProperty = getVertexByProperty(keyName, keyValue);
324       if (vertexByProperty.isLeft()) {
325           try {
326               Vertex vertex = vertexByProperty.left().value();
327               Map<String, Object> properties = getProperties(vertex);
328               T node = GraphElementFactory
329                   .createElement((String) properties.get(GraphPropertiesDictionary.LABEL.getProperty()), GraphElementTypeEnum.Node, properties,
330                       clazz);
331               return Either.left(node);
332           } catch (Exception e) {
333               log.debug("Failed to get node for key [{}] with value [{}] ", keyName, keyValue, e);
334               return Either.right(JanusGraphClient.handleJanusGraphException(e));
335           }
336       } else {
337           log.debug("Failed to get node for key [{}] with value [{}]  ", keyName, keyValue, vertexByProperty.right().value());
338           return Either.right(vertexByProperty.right().value());
339       }
340     }
341     
342     public <T extends GraphNode> Either<T, JanusGraphOperationStatus> getNode(final String keyName, final Object keyValue, final Class<T> clazz, final String model) {
343         log.debug("Try to get node for key [{}] with value [{}] ", keyName, keyValue);
344         final Either<JanusGraphVertex, JanusGraphOperationStatus> vertexByProperty = getVertexByPropertyForModel(keyName, keyValue, model);
345         if (vertexByProperty.isLeft()) {
346             try {
347                 final Vertex vertex = vertexByProperty.left().value();
348                 final Map<String, Object> properties = getProperties(vertex);
349                 final T node = GraphElementFactory
350                     .createElement((String) properties.get(GraphPropertiesDictionary.LABEL.getProperty()), GraphElementTypeEnum.Node, properties,
351                         clazz);
352                 return Either.left(node);
353             } catch (final Exception e) {
354                 log.debug("Failed to get node for key [{}] with value [{}] ", keyName, keyValue, e);
355                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
356             }
357         } else {
358             log.debug("Failed to get node for key [{}] with value [{}]  ", keyName, keyValue, vertexByProperty.right().value());
359             return Either.right(vertexByProperty.right().value());
360         }
361     }
362
363     /**
364      * @param from
365      * @param to
366      * @param label
367      * @return
368      */
369     public Either<GraphRelation, JanusGraphOperationStatus> getRelation(GraphNode from, GraphNode to, GraphEdgeLabels label) {
370         log.debug("try to get relation from [{}] to [{}]", from.getKeyValueId(), to.getKeyValueId());
371         Either<Edge, JanusGraphOperationStatus> edge = getEdgeByNodes(from, to, label);
372         if (edge.isLeft()) {
373             try {
374                 Map<String, Object> properties = getProperties(edge.left().value());
375                 GraphRelation relation = GraphElementFactory.createRelation(label.getProperty(), properties, from, to);
376                 return Either.left(relation);
377             } catch (Exception e) {
378                 log.debug("Failed to get  get relation from [{}] to [{}]", from.getKeyValueId(), to.getKeyValueId(), e);
379                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
380             }
381         } else {
382             log.debug("Failed to get  get relation from [{}] to [{}]   {}", from.getKeyValueId(), to.getKeyValueId(), edge.right().value());
383             return Either.right(edge.right().value());
384         }
385     }
386
387     public Either<Edge, JanusGraphOperationStatus> getEdgeByNodes(GraphNode from, GraphNode to, GraphEdgeLabels label) {
388         ImmutablePair<String, Object> keyValueIdFrom = from.getKeyValueId();
389         ImmutablePair<String, Object> keyValueIdTo = to.getKeyValueId();
390         return getEdgeByVerticies(keyValueIdFrom.getKey(), keyValueIdFrom.getValue(), keyValueIdTo.getKey(), keyValueIdTo.getValue(),
391             label.getProperty());
392     }
393
394     public Either<GraphRelation, JanusGraphOperationStatus> deleteIncomingRelationByCriteria(GraphNode to, GraphEdgeLabels label,
395                                                                                              Map<String, Object> props) {
396         Either<Edge, JanusGraphOperationStatus> edgeByCriteria = getIncomingEdgeByCriteria(to, label, props);
397         if (edgeByCriteria.isLeft()) {
398             Either<JanusGraph, JanusGraphOperationStatus> graph = getGraph();
399             if (graph.isLeft()) {
400                 Edge edge = edgeByCriteria.left().value();
401                 log.debug("delete edge {} to {} ", label.getProperty(), to.getUniqueId());
402                 edge.remove();
403                 Map<String, Object> properties = getProperties(edge);
404                 Vertex fromVertex = edge.outVertex();
405                 String fromLabel = fromVertex.value(GraphPropertiesDictionary.LABEL.getProperty());
406                 GraphNode nodeFrom = GraphElementFactory
407                     .createElement(fromLabel, GraphElementTypeEnum.Node, getProperties(fromVertex), GraphNode.class);
408                 GraphRelation relation = GraphElementFactory.createRelation(label.getProperty(), properties, nodeFrom, to);
409                 return Either.left(relation);
410             } else {
411                 log.debug("failed to get graph");
412                 return Either.right(graph.right().value());
413             }
414         } else {
415             log.debug("failed to find edge {} to {}", label.getProperty(), to.getUniqueId());
416             return Either.right(edgeByCriteria.right().value());
417         }
418     }
419
420     public Either<GraphRelation, JanusGraphOperationStatus> getIncomingRelationByCriteria(GraphNode to, GraphEdgeLabels label,
421                                                                                           Map<String, Object> props) {
422         Either<Edge, JanusGraphOperationStatus> edgeByCriteria = getIncomingEdgeByCriteria(to, label, props);
423         if (edgeByCriteria.isLeft()) {
424             Either<JanusGraph, JanusGraphOperationStatus> graph = getGraph();
425             if (graph.isLeft()) {
426                 Edge edge = edgeByCriteria.left().value();
427                 Map<String, Object> properties = getProperties(edge);
428                 Vertex fromVertex = edge.outVertex();
429                 String fromLabel = fromVertex.value(GraphPropertiesDictionary.LABEL.getProperty());
430                 GraphNode nodeFrom = GraphElementFactory
431                     .createElement(fromLabel, GraphElementTypeEnum.Node, getProperties(fromVertex), GraphNode.class);
432                 GraphRelation relation = GraphElementFactory.createRelation(label.getProperty(), properties, nodeFrom, to);
433                 return Either.left(relation);
434             } else {
435                 log.debug("failed to get graph");
436                 return Either.right(graph.right().value());
437             }
438         } else {
439             log.debug("failed to find edge {} to {}", label.getProperty(), to.getUniqueId());
440             return Either.right(edgeByCriteria.right().value());
441         }
442     }
443
444     public Either<Edge, JanusGraphOperationStatus> getIncomingEdgeByCriteria(GraphNode to, GraphEdgeLabels label, Map<String, Object> props) {
445         ImmutablePair<String, Object> keyValueIdTo = to.getKeyValueId();
446         Either<JanusGraphVertex, JanusGraphOperationStatus> vertexFrom = getVertexByProperty(keyValueIdTo.getKey(), keyValueIdTo.getValue());
447         if (vertexFrom.isRight()) {
448             return Either.right(vertexFrom.right().value());
449         }
450         Vertex vertex = vertexFrom.left().value();
451         JanusGraphVertex janusGraphVertex = (JanusGraphVertex) vertex;
452         JanusGraphVertexQuery<?> query = janusGraphVertex.query();
453         query = query.labels(label.getProperty());
454         if (props != null && !props.isEmpty()) {
455             for (Map.Entry<String, Object> entry : props.entrySet()) {
456                 query = query.has(entry.getKey(), entry.getValue());
457             }
458         }
459         Edge matchingEdge = null;
460         Iterable<JanusGraphEdge> edges = query.edges();
461         if (edges == null) {
462             log.debug("No edges in graph for criteria");
463             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
464         }
465         Iterator<JanusGraphEdge> eIter = edges.iterator();
466         if (eIter.hasNext()) {
467             matchingEdge = eIter.next();
468         }
469         if (matchingEdge == null) {
470             log.debug("No edges in graph for criteria");
471             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
472         }
473         return Either.left(matchingEdge);
474     }
475
476     public Either<Edge, JanusGraphOperationStatus> getEdgeByVerticies(String keyNameFrom, Object keyValueFrom, String keyNameTo, Object keyValueTo,
477                                                                       String label) {
478         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
479         if (graph.isLeft()) {
480             try {
481                 Either<JanusGraphVertex, JanusGraphOperationStatus> vertexFrom = getVertexByProperty(keyNameFrom, keyValueFrom);
482                 if (vertexFrom.isRight()) {
483                     return Either.right(vertexFrom.right().value());
484                 }
485                 Iterable<JanusGraphEdge> edges = ((JanusGraphVertex) vertexFrom.left().value()).query().labels(label).edges();
486                 Iterator<JanusGraphEdge> eIter = edges.iterator();
487                 while (eIter.hasNext()) {
488                     Edge edge = eIter.next();
489                     Vertex vertexIn = edge.inVertex();
490                     if (vertexIn.value(keyNameTo) != null && vertexIn.value(keyNameTo).equals(keyValueTo) && label.equals(edge.label())) {
491                         return Either.left(edge);
492                     }
493                 }
494                 log.debug("No relation in graph from [{}={}] to [{}={}]", keyNameFrom, keyValueFrom, keyNameTo, keyValueTo);
495                 return Either.right(JanusGraphOperationStatus.NOT_FOUND);
496             } catch (Exception e) {
497                 log.debug("Failed to get  get relation from [{}={}] to [{}={}]", keyNameFrom, keyValueFrom, keyNameTo, keyValueTo, e);
498                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
499             }
500         } else {
501             return Either.right(graph.right().value());
502         }
503     }
504
505     public Either<List<Edge>, JanusGraphOperationStatus> getEdgesForNode(GraphNode node, Direction requestedDirection) {
506         Either<List<Edge>, JanusGraphOperationStatus> result;
507         ImmutablePair<String, Object> keyValueId = node.getKeyValueId();
508         Either<JanusGraphVertex, JanusGraphOperationStatus> eitherVertex = getVertexByProperty(keyValueId.getKey(), keyValueId.getValue());
509         if (eitherVertex.isLeft()) {
510             List<Edge> edges = prepareEdgesList(eitherVertex.left().value(), requestedDirection);
511             result = Either.left(edges);
512         } else {
513             result = Either.right(eitherVertex.right().value());
514         }
515         return result;
516     }
517
518     private List<Edge> prepareEdgesList(Vertex vertex, Direction requestedDirection) {
519         List<Edge> edges = new ArrayList<>();
520         Iterator<JanusGraphEdge> edgesItr = ((JanusGraphVertex) vertex).query().edges().iterator();
521         while (edgesItr.hasNext()) {
522             Edge edge = edgesItr.next();
523             Direction currEdgeDirection = getEdgeDirection(vertex, edge);
524             if (currEdgeDirection == requestedDirection || requestedDirection == Direction.BOTH) {
525                 edges.add(edge);
526             }
527         }
528         return edges;
529     }
530
531     private Direction getEdgeDirection(Vertex vertex, Edge edge) {
532         Direction result;
533         Vertex vertexOut = edge.outVertex();
534         if (vertexOut.equals(vertex)) {
535             result = Direction.OUT;
536         } else {
537             result = Direction.IN;
538         }
539         return result;
540     }
541
542     /**
543      * @param from
544      * @param to
545      * @param label
546      * @param properties
547      * @return
548      */
549     public Either<GraphRelation, JanusGraphOperationStatus> updateRelation(GraphNode from, GraphNode to, GraphEdgeLabels label,
550                                                                            Map<String, Object> properties) {
551         log.debug("try to update relation from [{}] to [{}]", from.getKeyValueId(), to.getKeyValueId());
552         return updateEdge(label.getProperty(), from.getKeyValueId(), to.getKeyValueId(), from.getLabel(), to.getLabel(), properties);
553     }
554
555     private Either<GraphRelation, JanusGraphOperationStatus> updateEdge(String type, ImmutablePair<String, Object> from,
556                                                                         ImmutablePair<String, Object> to, String fromLabel, String toLabel,
557                                                                         Map<String, Object> properties) {
558         Either<Edge, JanusGraphOperationStatus> edgeS = getEdgeByVerticies(from.getKey(), from.getValue(), to.getKey(), to.getValue(), type);
559         if (edgeS.isLeft()) {
560             try {
561                 Edge edge = edgeS.left().value();
562                 if (properties != null) {
563                     setProperties(edge, properties);
564                 }
565                 Vertex vertexOut = edge.outVertex();
566                 Vertex vertexIn = edge.inVertex();
567                 GraphNode nodeOut = GraphElementFactory
568                     .createElement(fromLabel, GraphElementTypeEnum.Node, getProperties(vertexOut), GraphNode.class);
569                 GraphNode nodeIn = GraphElementFactory.createElement(toLabel, GraphElementTypeEnum.Node, getProperties(vertexIn), GraphNode.class);
570                 GraphRelation newRelation = GraphElementFactory.createRelation(edge.label(), getProperties(edge), nodeOut, nodeIn);
571                 if (log.isDebugEnabled()) {
572                     log.debug("Relation was updated from [{}] to [{}] ", from, to);
573                 }
574                 return Either.left(newRelation);
575             } catch (Exception e) {
576                 if (log.isDebugEnabled()) {
577                     log.debug("Failed to update relation from [{}] to [{}] ", from, to, e);
578                 }
579                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
580             }
581         } else {
582             if (log.isDebugEnabled()) {
583                 log.debug("Failed to update relation from [{}] to [{}] {}", from, to, edgeS.right().value());
584             }
585             return Either.right(edgeS.right().value());
586         }
587     }
588
589     /**
590      * @param relation
591      * @return
592      */
593     public Either<GraphRelation, JanusGraphOperationStatus> updateRelation(GraphRelation relation) {
594         log.debug("try to update relation from [{}] to [{}]", relation.getFrom(), relation.getTo());
595         RelationEndPoint from = relation.getFrom();
596         RelationEndPoint to = relation.getTo();
597         ImmutablePair<String, Object> fromKeyId = new ImmutablePair<>(from.getIdName(), from.getIdValue());
598         ImmutablePair<String, Object> toKeyId = new ImmutablePair<>(to.getIdName(), to.getIdValue());
599         return updateEdge(relation.getType(), fromKeyId, toKeyId, from.getLabel().getName(), to.getLabel().getName(), relation.toGraphMap());
600     }
601
602     private Either<Vertex, JanusGraphOperationStatus> getVertexByPropertyAndLabel(String name, Object value, String label) {
603         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
604         if (graph.isLeft()) {
605             try {
606                 JanusGraph tGraph = graph.left().value();
607                 @SuppressWarnings("unchecked") Iterable<JanusGraphVertex> vertecies = tGraph.query().has(name, value)
608                     .has(GraphPropertiesDictionary.LABEL.getProperty(), label).vertices();
609                 java.util.Iterator<JanusGraphVertex> iterator = vertecies.iterator();
610                 if (iterator.hasNext()) {
611                     Vertex vertex = iterator.next();
612                     return Either.left(vertex);
613                 }
614                 if (log.isDebugEnabled()) {
615                     log.debug("No vertex in graph for key =" + name + " and value = " + value + "  label = " + label);
616                 }
617                 return Either.right(JanusGraphOperationStatus.NOT_FOUND);
618             } catch (Exception e) {
619                 if (log.isDebugEnabled()) {
620                     log.debug("Failed to get vertex in graph for key ={} and value = {} label = {}", name, value, label);
621                 }
622                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
623             }
624         } else {
625             if (log.isDebugEnabled()) {
626                 log.debug("No vertex in graph for key ={} and value = {}  label = {} error : {}", name, value, label, graph.right().value());
627             }
628             return Either.right(graph.right().value());
629         }
630     }
631     
632     public Either<JanusGraphVertex, JanusGraphOperationStatus> getVertexByPropertyForModel(final String name, final Object value, final String model) {
633         final Either<Iterable<JanusGraphVertex>, JanusGraphOperationStatus> vertices = getVerticesByProperty(name, value);
634               
635         if (vertices.isLeft()) {
636             final Predicate<? super JanusGraphVertex> filterPredicate = StringUtils.isEmpty(model) ? this::vertexNotConnectedToAnyModel : vertex -> vertexValidForModel(vertex, model);
637             final List<JanusGraphVertex> verticesForModel = StreamSupport.stream(vertices.left().value().spliterator(), false).filter(filterPredicate).collect(Collectors.toList());
638         
639             if (CollectionUtils.isEmpty(verticesForModel)) {
640                 if (log.isDebugEnabled()) {
641                     log.debug("No vertex in graph for key ={} and value = {}", name, value);
642                 }
643                 return Either.right(JanusGraphOperationStatus.NOT_FOUND);
644             }
645             return Either.left(verticesForModel.get(0));
646         }
647         return Either.right(vertices.right().value());
648     }
649     
650     public Either<JanusGraphVertex, JanusGraphOperationStatus> getVertexByProperty(final String name, final Object value) {
651         final Either<Iterable<JanusGraphVertex>, JanusGraphOperationStatus> vertices = getVerticesByProperty(name, value);
652         if (vertices.isLeft()) {
653             return Either.left(vertices.left().value().iterator().next());
654         }
655         return Either.right(vertices.right().value());
656     }
657
658     
659     public Either<Iterable<JanusGraphVertex>, JanusGraphOperationStatus> getVerticesByProperty(final String name, final Object value) {
660         final Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
661         if (value == null) {
662             if (log.isDebugEnabled()) {
663                 log.debug("No vertex in graph for key = {} and value = {}", name, value);
664             }
665           return Either.right(JanusGraphOperationStatus.NOT_FOUND);
666         }
667         if (graph.isLeft()) {
668             try {
669                 final JanusGraph tGraph = graph.left().value();
670                 @SuppressWarnings("unchecked") Iterable<JanusGraphVertex> vertices = tGraph.query().has(name, value).vertices();
671                 if (vertices.iterator().hasNext()) {
672                     return Either.left(vertices);
673                 } else {
674                     if (log.isDebugEnabled()) {
675                         log.debug("No vertex in graph for key ={} and value = {}", name, value);
676                     }
677                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
678                 }
679             } catch (Exception e) {
680                 if (log.isDebugEnabled()) {
681                     log.debug("Failed to get vertex in graph for key = {} and value = ", name, value);
682                 }
683                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
684             }
685         } else {
686             if (log.isDebugEnabled()) {
687                 log.debug("No vertex in graph for key = {} and value = {} error : {}", name, value, graph.right().value());
688             }
689             return Either.right(graph.right().value());
690         }
691     }
692     
693     private boolean vertexValidForModel(final JanusGraphVertex vertex, final String model) {
694         final Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> modelVertices = getParentVerticies(vertex, GraphEdgeLabels.MODEL_ELEMENT);
695
696         if (modelVertices.isLeft()) {
697             for (ImmutablePair<JanusGraphVertex, Edge> vertexPair : modelVertices.left().value()) {
698                 if (modelVertexMatchesModel(vertexPair.getLeft(), model)) {
699                     return true;
700                 }
701             }
702         }
703         return false;
704     }
705     
706     private boolean modelVertexMatchesModel(final JanusGraphVertex modelVertex, final String model) {
707         if (model.equals((String)modelVertex.property("name").value())) {
708             return true;
709         }
710         final Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> derivedModels =
711                         getParentVerticies(modelVertex, GraphEdgeLabels.DERIVED_FROM);
712         if (derivedModels.isLeft()) {
713             for (final ImmutablePair<JanusGraphVertex, Edge> derivedModel : derivedModels.left().value()) {
714                 if (modelVertexMatchesModel(derivedModel.left, model)) {
715                     return true;
716                 }
717             }
718         }
719         return false;
720     }
721     
722     private boolean vertexNotConnectedToAnyModel(final JanusGraphVertex vertex) {
723         return !vertex.edges(Direction.IN, EdgeLabelEnum.MODEL_ELEMENT.name()).hasNext();
724     }
725
726
727     public <T extends GraphNode> Either<List<T>, JanusGraphOperationStatus> getByCriteria(NodeTypeEnum type, Map<String, Object> hasProps,
728                                                                                           Map<String, Object> hasNotProps, Class<T> clazz) {
729         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
730         if (graph.isLeft()) {
731             try {
732                 JanusGraph tGraph = graph.left().value();
733                 JanusGraphQuery<? extends JanusGraphQuery> query = tGraph.query();
734                 query = query.has(GraphPropertiesDictionary.LABEL.getProperty(), type.getName());
735                 if (hasProps != null && !hasProps.isEmpty()) {
736                     for (Map.Entry<String, Object> entry : hasProps.entrySet()) {
737                         query = query.has(entry.getKey(), entry.getValue());
738                     }
739                 }
740                 if (hasNotProps != null && !hasNotProps.isEmpty()) {
741                     for (Map.Entry<String, Object> entry : hasNotProps.entrySet()) {
742                         query = query.hasNot(entry.getKey(), entry.getValue());
743                     }
744                 }
745                 Iterable<JanusGraphVertex> vertices = query.vertices();
746                 if (vertices == null) {
747                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
748                 }
749                 Iterator<JanusGraphVertex> iterator = vertices.iterator();
750                 List<T> result = new ArrayList<>();
751                 while (iterator.hasNext()) {
752                     Vertex vertex = iterator.next();
753                     Map<String, Object> newProp = getProperties(vertex);
754                     T element = GraphElementFactory.createElement(type.getName(), GraphElementTypeEnum.Node, newProp, clazz);
755                     result.add(element);
756                 }
757                 if (log.isDebugEnabled()) {
758                     log.debug("Number of fetced nodes in graph for criteria : from type = {} and properties has = {}, properties hasNot = {}  is {}",
759                         type, hasProps, hasNotProps, result.size());
760                 }
761                 if (result.size() == 0) {
762                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
763                 }
764                 return Either.left(result);
765             } catch (Exception e) {
766                 if (log.isDebugEnabled()) {
767                     log.debug("Failed  get by  criteria for type = {}", type, e);
768                 }
769                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
770             }
771         } else {
772             if (log.isDebugEnabled()) {
773                 log.debug("Failed  get by  criteria for type ={}  error : {}", type, graph.right().value());
774             }
775             return Either.right(graph.right().value());
776         }
777     }
778
779     public <T extends GraphNode> Either<List<T>, JanusGraphOperationStatus> getByCriteria(NodeTypeEnum type, Class<T> clazz,
780                                                                                           List<ImmutableTriple<QueryType, String, Object>> props) {
781         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
782         if (graph.isLeft()) {
783             try {
784                 JanusGraph tGraph = graph.left().value();
785                 JanusGraphQuery<? extends JanusGraphQuery> query = tGraph.query();
786                 query = query.has(GraphPropertiesDictionary.LABEL.getProperty(), type.getName());
787                 for (ImmutableTriple<QueryType, String, Object> prop : props) {
788                     if (QueryType.HAS.equals(prop.getLeft())) {
789                         query = query.has(prop.getMiddle(), prop.getRight());
790                     } else {
791                         query = query.hasNot(prop.getMiddle(), prop.getRight());
792                     }
793                 }
794                 Iterable<JanusGraphVertex> vertices = query.vertices();
795                 if (vertices == null) {
796                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
797                 }
798                 Iterator<JanusGraphVertex> iterator = vertices.iterator();
799                 List<T> result = new ArrayList<>();
800                 while (iterator.hasNext()) {
801                     Vertex vertex = iterator.next();
802                     Map<String, Object> newProp = getProperties(vertex);
803                     T element = GraphElementFactory.createElement(type.getName(), GraphElementTypeEnum.Node, newProp, clazz);
804                     result.add(element);
805                 }
806                 if (result.size() == 0) {
807                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
808                 }
809                 return Either.left(result);
810             } catch (Exception e) {
811                 if (log.isDebugEnabled()) {
812                     log.debug("Failed  get by  criteria for type = {}", type, e);
813                 }
814                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
815             }
816         } else {
817             if (log.isDebugEnabled()) {
818                 log.debug("Failed  get by  criteria for type ={}  error : {}", type, graph.right().value());
819             }
820             return Either.right(graph.right().value());
821         }
822     }
823
824     public <T extends GraphNode> Either<List<T>, JanusGraphOperationStatus> getByCriteria(NodeTypeEnum type, Map<String, Object> props,
825                                                                                           Class<T> clazz) {
826         return getByCriteriaForModel(type, props, null, clazz);
827     }
828     
829     public <T extends GraphNode> Either<List<T>, JanusGraphOperationStatus> getByCriteriaForModel(final NodeTypeEnum type, final Map<String, Object> props,
830             final String model, final Class<T> clazz) {
831         try {
832             final Either<Iterable<JanusGraphVertex>, JanusGraphOperationStatus> vertices = getVerticesByCriteria(type, props);
833             
834             if (vertices.isLeft()) {
835                 final Predicate<? super JanusGraphVertex> filterPredicate = StringUtils.isEmpty(model) ? this::vertexNotConnectedToAnyModel : vertex -> vertexValidForModel(vertex, model);
836                 final List<JanusGraphVertex> verticesForModel = StreamSupport.stream(vertices.left().value().spliterator(), false).filter(filterPredicate).collect(Collectors.toList());
837             
838                 if (CollectionUtils.isEmpty(verticesForModel)) {
839                     log.debug("No vertex in graph for props ={} ", props);
840                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
841                 }
842   
843                 final Iterator<JanusGraphVertex> iterator = verticesForModel.iterator();
844                 final List<T> result = new ArrayList<>();
845                 while (iterator.hasNext()) {
846                     Vertex vertex = iterator.next();
847                     Map<String, Object> newProp = getProperties(vertex);
848                     T element = GraphElementFactory.createElement(type.getName(), GraphElementTypeEnum.Node, newProp, clazz);
849                     result.add(element);
850                 }
851                 log.debug("Number of fetced nodes in graph for criteria : from type = {} and properties = {} is {}", type, props, result.size());
852                 return Either.left(result);
853
854             }
855             return Either.right(vertices.right().value());
856         } catch (Exception e) {
857             log.debug("Failed  get by  criteria for type = {} and properties = {}", type, props, e);
858             return Either.right(JanusGraphClient.handleJanusGraphException(e));
859         }
860     }
861     
862     private Either<Iterable<JanusGraphVertex>, JanusGraphOperationStatus> getVerticesByCriteria(final NodeTypeEnum type, final Map<String, Object> props) {
863         final Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
864         if (graph.isLeft()) {
865             try {
866                 final JanusGraph tGraph = graph.left().value();
867                 JanusGraphQuery<? extends JanusGraphQuery> query = tGraph.query();
868                 query = query.has(GraphPropertiesDictionary.LABEL.getProperty(), type.getName());
869                 if (props != null && !props.isEmpty()) {
870                     for (Map.Entry<String, Object> entry : props.entrySet()) {
871                         query = query.has(entry.getKey(), entry.getValue());
872                     }
873                 }
874                 final Iterable<JanusGraphVertex> vertices = query.vertices();
875                 if (vertices == null || !vertices.iterator().hasNext()) {
876                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
877                 }
878                 return Either.left(vertices);
879             } catch (Exception e) {
880                 if (log.isDebugEnabled()) {
881                     log.debug("Failed  get by  criteria for type = {} and properties = {}", type, props, e);
882                 }
883                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
884             }
885         } else {
886             if (log.isDebugEnabled()) {
887                 log.debug("Failed  get by  criteria for type ={} and properties = {} error : {}", type, props, graph.right().value());
888             }
889             return Either.right(graph.right().value());
890         }
891     }
892
893     public <T extends GraphNode> Either<List<T>, JanusGraphOperationStatus> getByCriteriaWithPredicate(NodeTypeEnum type,
894                                                                                                        Map<String, Entry<JanusGraphPredicate, Object>> props,
895                                                                                                        Class<T> clazz, String modelName) {
896         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
897         if (graph.isLeft()) {
898             try {
899                 JanusGraph tGraph = graph.left().value();
900                 JanusGraphQuery<? extends JanusGraphQuery> query = tGraph.query();
901                 query = query.has(GraphPropertiesDictionary.LABEL.getProperty(), type.getName());
902                 if (props != null && !props.isEmpty()) {
903                     JanusGraphPredicate predicate = null;
904                     Object object = null;
905                     for (Map.Entry<String, Entry<JanusGraphPredicate, Object>> entry : props.entrySet()) {
906                         predicate = entry.getValue().getKey();
907                         object = entry.getValue().getValue();
908                         query = query.has(entry.getKey(), predicate, object);
909                     }
910                 }
911                 Iterable<JanusGraphVertex> vertices = query.vertices();
912                 if (vertices == null) {
913                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
914                 }
915                 final Predicate<? super JanusGraphVertex> filterPredicate =
916                     StringUtils.isEmpty(modelName) ? this::vertexNotConnectedToAnyModel : vertex -> vertexValidForModel(vertex, modelName);
917                 final List<JanusGraphVertex> verticesForModel = StreamSupport.stream(vertices.spliterator(), false).filter(filterPredicate)
918                     .collect(Collectors.toList());
919                 Iterator<JanusGraphVertex> iterator = verticesForModel.iterator();
920                 List<T> result = new ArrayList<>();
921                 while (iterator.hasNext()) {
922                     Vertex vertex = iterator.next();
923                     Map<String, Object> newProp = getProperties(vertex);
924                     T element = GraphElementFactory.createElement(type.getName(), GraphElementTypeEnum.Node, newProp, clazz);
925                     result.add(element);
926                 }
927                 if (result.size() == 0) {
928                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
929                 }
930                 if (log.isDebugEnabled()) {
931                     log.debug("No nodes in graph for criteria : from type = {} and properties = {}", type, props);
932                 }
933                 return Either.left(result);
934             } catch (Exception e) {
935                 if (log.isDebugEnabled()) {
936                     log.debug("Failed  get by  criteria for type = {} and properties = {}", type, props, e);
937                 }
938                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
939             }
940         } else {
941             if (log.isDebugEnabled()) {
942                 log.debug("Failed  get by  criteria for type = {} and properties = {} error : {}", type, props, graph.right().value());
943             }
944             return Either.right(graph.right().value());
945         }
946     }
947
948     public <T extends GraphNode> Either<List<T>, JanusGraphOperationStatus> getAll(NodeTypeEnum type, Class<T> clazz) {
949         return getByCriteria(type, null, clazz);
950     }
951
952     /**
953      * @param node
954      * @param clazz
955      * @return
956      */
957     public <T extends GraphNode> Either<T, JanusGraphOperationStatus> updateNode(GraphNode node, Class<T> clazz) {
958         log.debug("Try to update node for {}", node.getKeyValueIdForLog());
959         ImmutablePair<String, Object> keyValueId = node.getKeyValueId();
960         Either<Vertex, JanusGraphOperationStatus> vertexByProperty = getVertexByPropertyAndLabel(keyValueId.getKey(), keyValueId.getValue(),
961             node.getLabel());
962         if (vertexByProperty.isLeft()) {
963             try {
964                 Vertex vertex = vertexByProperty.left().value();
965                 Map<String, Object> mapProps = node.toGraphMap();
966                 for (Map.Entry<String, Object> entry : mapProps.entrySet()) {
967                     if (!entry.getKey().equals(node.getUniqueIdKey())) {
968                         vertex.property(entry.getKey(), entry.getValue());
969                     }
970                 }
971                 Either<Vertex, JanusGraphOperationStatus> vertexByPropertyAndLabel = getVertexByPropertyAndLabel(keyValueId.getKey(),
972                     keyValueId.getValue(), node.getLabel());
973                 if (vertexByPropertyAndLabel.isRight()) {
974                     return Either.right(vertexByPropertyAndLabel.right().value());
975                 } else {
976                     Map<String, Object> newProp = getProperties(vertexByPropertyAndLabel.left().value());
977                     T updateNode = GraphElementFactory.createElement(node.getLabel(), GraphElementTypeEnum.Node, newProp, clazz);
978                     return Either.left(updateNode);
979                 }
980             } catch (Exception e) {
981                 if (log.isDebugEnabled()) {
982                     log.debug("Failed to update node for {}", node.getKeyValueId(), e);
983                 }
984                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
985             }
986         } else {
987             if (log.isDebugEnabled()) {
988                 log.debug("Failed to update node for {} error :{}", node.getKeyValueIdForLog(), vertexByProperty.right().value());
989             }
990             return Either.right(vertexByProperty.right().value());
991         }
992     }
993
994     public JanusGraphOperationStatus updateVertex(GraphNode node, Vertex vertex) {
995         log.debug("Try to update node for {}", node.getKeyValueId());
996         try {
997             Map<String, Object> mapProps = node.toGraphMap();
998             for (Map.Entry<String, Object> entry : mapProps.entrySet()) {
999                 if (!entry.getKey().equals(node.getUniqueIdKey())) {
1000                     vertex.property(entry.getKey(), entry.getValue());
1001                 }
1002             }
1003         } catch (Exception e) {
1004             if (log.isDebugEnabled()) {
1005                 log.debug("Failed to update node for {}", node.getKeyValueId(), e);
1006             }
1007             return JanusGraphClient.handleJanusGraphException(e);
1008         }
1009         return JanusGraphOperationStatus.OK;
1010     }
1011
1012     /**
1013      * @param node
1014      * @param clazz
1015      * @return
1016      */
1017     public <T extends GraphNode> Either<T, JanusGraphOperationStatus> deleteNode(GraphNode node, Class<T> clazz) {
1018         log.debug("Try to delete node for {}", node.getKeyValueId());
1019         ImmutablePair<String, Object> keyValueId = node.getKeyValueId();
1020         return deleteNode(keyValueId.getKey(), keyValueId.getValue(), clazz);
1021     }
1022
1023     /**
1024      * @param keyName
1025      * @param keyValue
1026      * @param clazz
1027      * @return
1028      */
1029     public <T extends GraphNode> Either<T, JanusGraphOperationStatus> deleteNode(String keyName, Object keyValue, Class<T> clazz) {
1030         Either<JanusGraphVertex, JanusGraphOperationStatus> vertexByProperty = getVertexByProperty(keyName, keyValue);
1031         if (vertexByProperty.isLeft()) {
1032             try {
1033                 Vertex vertex = vertexByProperty.left().value();
1034                 Map<String, Object> properties = getProperties(vertex);
1035                 if (properties != null) {
1036                     String label = (String) properties.get(GraphPropertiesDictionary.LABEL.getProperty());
1037                     T node = GraphElementFactory.createElement(label, GraphElementTypeEnum.Node, properties, clazz);
1038                     if (node != null) {
1039                         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
1040                         if (graph.isLeft()) {
1041                             JanusGraph tGraph = graph.left().value();
1042                             vertex.remove();
1043                         } else {
1044                             return Either.right(graph.right().value());
1045                         }
1046                         return Either.left(node);
1047                     } else {
1048                         if (log.isDebugEnabled()) {
1049                             log.debug("Failed to delete node for {} = {} Missing label property on node", keyName, keyValue);
1050                         }
1051                         return Either.right(JanusGraphOperationStatus.MISSING_NODE_LABEL);
1052                     }
1053                 } else {
1054                     if (log.isDebugEnabled()) {
1055                         log.debug("Failed to delete node for {} = {} Missing label property on node", keyName, keyValue);
1056                     }
1057                     return Either.right(JanusGraphOperationStatus.MISSING_NODE_LABEL);
1058                 }
1059             } catch (Exception e) {
1060                 if (log.isDebugEnabled()) {
1061                     log.debug("Failed to delete node for {} = {}", keyName, keyValue, e);
1062                 }
1063                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
1064             }
1065         } else {
1066             return Either.right(vertexByProperty.right().value());
1067         }
1068     }
1069
1070     public Either<GraphRelation, JanusGraphOperationStatus> deleteRelation(GraphRelation relation) {
1071         log.debug("try to delete relation from [{}] to [{}]", relation.getFrom(), relation.getTo());
1072         RelationEndPoint from = relation.getFrom();
1073         RelationEndPoint to = relation.getTo();
1074         ImmutablePair<String, Object> fromKeyId = new ImmutablePair<>(from.getIdName(), from.getIdValue());
1075         ImmutablePair<String, Object> toKeyId = new ImmutablePair<>(to.getIdName(), to.getIdValue());
1076         return deleteEdge(relation.getType(), fromKeyId, toKeyId, from.getLabel().getName(), to.getLabel().getName());
1077     }
1078
1079     public Either<Boolean, JanusGraphOperationStatus> isRelationExist(GraphNode from, GraphNode to, GraphEdgeLabels edgeLabel) {
1080         return getEdgeByNodes(from, to, edgeLabel).left().map(edge -> true).right()
1081             .bind(err -> err == JanusGraphOperationStatus.NOT_FOUND ? Either.left(false) : Either.right(err));
1082     }
1083
1084     public Either<GraphRelation, JanusGraphOperationStatus> deleteRelation(GraphNode from, GraphNode to, GraphEdgeLabels label) {
1085         log.debug("try to delete relation from [{}] to [{}]", from.getKeyValueId(), to.getKeyValueId());
1086         return deleteEdge(label.getProperty(), from.getKeyValueId(), to.getKeyValueId(), from.getLabel(), to.getLabel());
1087     }
1088
1089     private Either<GraphRelation, JanusGraphOperationStatus> deleteEdge(String type, ImmutablePair<String, Object> fromKeyId,
1090                                                                         ImmutablePair<String, Object> toKeyId, String fromLabel, String toLabel) {
1091         Either<Edge, JanusGraphOperationStatus> edgeS = getEdgeByVerticies(fromKeyId.getKey(), fromKeyId.getValue(), toKeyId.getKey(),
1092             toKeyId.getValue(), type);
1093         if (edgeS.isLeft()) {
1094             try {
1095                 Edge edge = edgeS.left().value();
1096                 Vertex vertexOut = edge.outVertex();
1097                 Vertex vertexIn = edge.inVertex();
1098                 GraphNode nodeOut = GraphElementFactory
1099                     .createElement(fromLabel, GraphElementTypeEnum.Node, getProperties(vertexOut), GraphNode.class);
1100                 GraphNode nodeIn = GraphElementFactory.createElement(toLabel, GraphElementTypeEnum.Node, getProperties(vertexIn), GraphNode.class);
1101                 GraphRelation newRelation = GraphElementFactory.createRelation(edge.label(), getProperties(edge), nodeOut, nodeIn);
1102                 Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
1103                 if (graph.isLeft()) {
1104                     edge.remove();
1105                     ;
1106                 } else {
1107                     if (log.isDebugEnabled()) {
1108                         log.debug("Failed to delete relation {} from {}  to {} error : {}", type, fromKeyId, toKeyId, graph.right().value());
1109                     }
1110                     return Either.right(graph.right().value());
1111                 }
1112                 return Either.left(newRelation);
1113             } catch (Exception e) {
1114                 if (log.isDebugEnabled()) {
1115                     log.debug("Failed to delete relation {} from {}  to {}", type, fromKeyId, toKeyId, e);
1116                 }
1117                 return Either.right(JanusGraphClient.handleJanusGraphException(e));
1118             }
1119         } else {
1120             if (log.isDebugEnabled()) {
1121                 log.debug("Failed to delete relation {} from {}  to {} error : {}", type, fromKeyId, toKeyId, edgeS.right().value());
1122             }
1123             return Either.right(edgeS.right().value());
1124         }
1125     }
1126
1127     public void setJanusGraphClient(JanusGraphClient janusGraphClient) {
1128         this.janusGraphClient = janusGraphClient;
1129     }
1130
1131     public Either<GraphRelation, JanusGraphOperationStatus> deleteIncomingRelation(GraphRelation relation) {
1132         RelationEndPoint to = relation.getTo();
1133         ImmutablePair<String, Object> toKeyId = new ImmutablePair<>(to.getIdName(), to.getIdValue());
1134         return deleteIncomingEdge(relation.getType(), toKeyId);
1135     }
1136
1137     private Either<GraphRelation, JanusGraphOperationStatus> deleteIncomingEdge(String type, ImmutablePair<String, Object> toKeyId) {
1138         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
1139         if (graph.isLeft()) {
1140             Either<JanusGraphVertex, JanusGraphOperationStatus> rootVertexResult = getVertexByProperty(toKeyId.getKey(), toKeyId.getValue());
1141             if (rootVertexResult.isLeft()) {
1142                 Vertex rootVertex = rootVertexResult.left().value();
1143                 Iterator<Edge> edgesIterator = rootVertex.edges(Direction.IN, type);
1144                 if (edgesIterator != null) {
1145                     Edge edge = null;
1146                     if (edgesIterator.hasNext()) {
1147                         edge = edgesIterator.next();
1148                         if (edgesIterator.hasNext()) {
1149                             return Either.right(JanusGraphOperationStatus.MULTIPLE_EDGES_WITH_SAME_LABEL);
1150                         }
1151                     } else {
1152                         return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1153                     }
1154                     log.debug("Find the tail vertex of the edge of type {} to vertex {}", type, toKeyId);
1155                     Vertex vertexOut = edge.outVertex();
1156                     String fromLabel = vertexOut.value(GraphPropertiesDictionary.LABEL.getProperty());
1157                     String toLabel = rootVertex.value(GraphPropertiesDictionary.LABEL.getProperty());
1158                     log.debug("The label of the outgoing vertex is {}", fromLabel);
1159                     GraphNode nodeOut = GraphElementFactory
1160                         .createElement(fromLabel, GraphElementTypeEnum.Node, getProperties(vertexOut), GraphNode.class);
1161                     GraphNode nodeIn = GraphElementFactory
1162                         .createElement(toLabel, GraphElementTypeEnum.Node, getProperties(rootVertex), GraphNode.class);
1163                     GraphRelation newRelation = GraphElementFactory.createRelation(edge.label(), getProperties(edge), nodeOut, nodeIn);
1164                     edge.remove();
1165                     return Either.left(newRelation);
1166                 } else {
1167                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1168                 }
1169             } else {
1170                 return Either.right(graph.right().value());
1171             }
1172         } else {
1173             return Either.right(graph.right().value());
1174         }
1175     }
1176
1177     public Either<GraphRelation, JanusGraphOperationStatus> deleteOutgoingRelation(GraphRelation relation) {
1178         RelationEndPoint from = relation.getFrom();
1179         ImmutablePair<String, Object> fromKeyId = new ImmutablePair<>(from.getIdName(), from.getIdValue());
1180         return deleteOutgoingEdge(relation.getType(), fromKeyId);
1181     }
1182
1183     private Either<GraphRelation, JanusGraphOperationStatus> deleteOutgoingEdge(String type, ImmutablePair<String, Object> toKeyId) {
1184         Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
1185         if (graph.isLeft()) {
1186             Either<JanusGraphVertex, JanusGraphOperationStatus> rootVertexResult = getVertexByProperty(toKeyId.getKey(), toKeyId.getValue());
1187             if (rootVertexResult.isLeft()) {
1188                 Vertex rootVertex = rootVertexResult.left().value();
1189                 Iterator<Edge> edgesIterator = rootVertex.edges(Direction.OUT, type);
1190                 if (edgesIterator != null) {
1191                     Edge edge = null;
1192                     if (edgesIterator.hasNext()) {
1193                         edge = edgesIterator.next();
1194                         if (edgesIterator.hasNext()) {
1195                             return Either.right(JanusGraphOperationStatus.MULTIPLE_EDGES_WITH_SAME_LABEL);
1196                         }
1197                     } else {
1198                         return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1199                     }
1200                     log.debug("Find the tail vertex of the edge of type {}  to vertex ", type, toKeyId);
1201                     Vertex vertexIn = edge.inVertex();
1202                     String toLabel = vertexIn.value(GraphPropertiesDictionary.LABEL.getProperty());
1203                     String fromLabel = rootVertex.value(GraphPropertiesDictionary.LABEL.getProperty());
1204                     log.debug("The label of the tail vertex is {}", toLabel);
1205                     GraphNode nodeFrom = GraphElementFactory
1206                         .createElement(fromLabel, GraphElementTypeEnum.Node, getProperties(rootVertex), GraphNode.class);
1207                     GraphNode nodeTo = GraphElementFactory
1208                         .createElement(toLabel, GraphElementTypeEnum.Node, getProperties(vertexIn), GraphNode.class);
1209                     GraphRelation newRelation = GraphElementFactory.createRelation(edge.label(), getProperties(edge), nodeFrom, nodeTo);
1210                     edge.remove();
1211                     return Either.left(newRelation);
1212                 } else {
1213                     return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1214                 }
1215             } else {
1216                 return Either.right(graph.right().value());
1217             }
1218         } else {
1219             return Either.right(graph.right().value());
1220         }
1221     }
1222
1223     /**
1224      * @param id
1225      * @return
1226      */
1227     public JanusGraphOperationStatus lockElement(String id, NodeTypeEnum type) {
1228         StringBuilder lockId = new StringBuilder(LOCK_NODE_PREFIX);
1229         lockId.append(type.getName()).append("_").append(id);
1230         return lockNode(lockId.toString());
1231     }
1232
1233     public JanusGraphOperationStatus lockElement(GraphNode node) {
1234         String lockId = createLockElementId(node);
1235         return lockNode(lockId);
1236     }
1237
1238     private JanusGraphOperationStatus lockNode(String lockId) {
1239         GraphNodeLock lockNode = new GraphNodeLock(lockId);
1240         Either<GraphNodeLock, JanusGraphOperationStatus> lockNodeNew = createNode(lockNode, GraphNodeLock.class);
1241         if (lockNodeNew.isLeft()) {
1242             log.debug("before commit, Lock node created for {}", lockId);
1243             return janusGraphClient.commit();
1244         } else {
1245             Either<JanusGraph, JanusGraphOperationStatus> graph = janusGraphClient.getGraph();
1246             if (graph.isLeft()) {
1247                 JanusGraph tGraph = graph.left().value();
1248                 Either<JanusGraphVertex, JanusGraphOperationStatus> vertex = getVertexByProperty(lockNode.getUniqueIdKey(), lockNode.getUniqueId());
1249                 if (vertex.isLeft()) {
1250                     return relockNode(lockNode, lockNodeNew, tGraph, vertex);
1251                 } else {
1252                     return vertex.right().value();
1253                 }
1254             } else {
1255                 return graph.right().value();
1256             }
1257         }
1258     }
1259
1260     private JanusGraphOperationStatus relockNode(GraphNodeLock lockNode, Either<GraphNodeLock, JanusGraphOperationStatus> lockNodeNew,
1261                                                  JanusGraph tGraph, Either<JanusGraphVertex, JanusGraphOperationStatus> vertex) {
1262         Long time = vertex.left().value().value(GraphPropertiesDictionary.CREATION_DATE.getProperty());
1263         Long lockTimeout = ConfigurationManager.getConfigurationManager().getConfiguration().getJanusGraphLockTimeout();
1264         if (time + lockTimeout * 1000 < System.currentTimeMillis()) {
1265             log.debug("Found not released lock node with id {}", lockNode.getUniqueId());
1266             vertex.left().value().remove();
1267             lockNodeNew = createNode(lockNode, GraphNodeLock.class);
1268             if (lockNodeNew.isLeft()) {
1269                 log.debug("Lock node created for {}", lockNode.getUniqueIdKey());
1270                 return janusGraphClient.commit();
1271             } else {
1272                 log.debug("Failed Lock node for {} .  Commit transacton for deleted previous vertex .", lockNode.getUniqueIdKey());
1273                 janusGraphClient.commit();
1274                 return checkLockError(lockNode.getUniqueIdKey(), lockNodeNew);
1275             }
1276         } else {
1277             log.debug("Failed Lock node for {}  rollback transacton", lockNode.getUniqueIdKey());
1278             janusGraphClient.rollback();
1279             return checkLockError(lockNode.getUniqueIdKey(), lockNodeNew);
1280         }
1281     }
1282
1283     public <T extends GraphNode> Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> getChildrenNodes(String key, String uniqueId,
1284                                                                                                                        GraphEdgeLabels edgeType,
1285                                                                                                                        NodeTypeEnum nodeTypeEnum,
1286                                                                                                                        Class<T> clazz,
1287                                                                                                                        boolean withEdges) {
1288         List<ImmutablePair<T, GraphEdge>> immutablePairs = new ArrayList<>();
1289         Either<JanusGraph, JanusGraphOperationStatus> graphRes = janusGraphClient.getGraph();
1290         if (graphRes.isRight()) {
1291             log.error("Failed to retrieve graph. status is {}", graphRes);
1292             return Either.right(graphRes.right().value());
1293         }
1294         JanusGraph janusGraph = graphRes.left().value();
1295         @SuppressWarnings("unchecked") Iterable<JanusGraphVertex> vertices = janusGraph.query().has(key, uniqueId).vertices();
1296         if (vertices == null || !vertices.iterator().hasNext()) {
1297             return Either.right(JanusGraphOperationStatus.INVALID_ID);
1298         }
1299         Vertex rootVertex = vertices.iterator().next();
1300         Iterator<Edge> edgesCreatorIterator = rootVertex.edges(Direction.OUT, edgeType.getProperty());
1301         if (edgesCreatorIterator != null) {
1302             while (edgesCreatorIterator.hasNext()) {
1303                 Edge edge = edgesCreatorIterator.next();
1304                 GraphEdge graphEdge = null;
1305                 if (withEdges) {
1306                     Map<String, Object> edgeProps = getProperties(edge);
1307                     GraphEdgeLabels edgeTypeFromGraph = GraphEdgeLabels.getByName(edge.label());
1308                     graphEdge = new GraphEdge(edgeTypeFromGraph, edgeProps);
1309                 }
1310                 Vertex outgoingVertex = edge.inVertex();
1311                 Map<String, Object> properties = getProperties(outgoingVertex);
1312                 T data = GraphElementFactory.createElement(nodeTypeEnum.getName(), GraphElementTypeEnum.Node, properties, clazz);
1313                 ImmutablePair<T, GraphEdge> immutablePair = new ImmutablePair<>(clazz.cast(data), graphEdge);
1314                 immutablePairs.add(immutablePair);
1315             }
1316         }
1317         if (immutablePairs.isEmpty()) {
1318             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1319         }
1320         return Either.left(immutablePairs);
1321     }
1322
1323     public <T extends GraphNode> JanusGraphOperationStatus deleteAllChildrenNodes(String key, String uniqueId, GraphEdgeLabels edgeType) {
1324         final JanusGraph janusGraph = getJanusGraph();
1325         final Iterable<JanusGraphVertex> vertices = janusGraph.query().has(key, uniqueId).vertices();
1326         if (vertices == null || !vertices.iterator().hasNext()) {
1327             return JanusGraphOperationStatus.NOT_FOUND;
1328         }
1329         final Vertex rootVertex = vertices.iterator().next();
1330         final Iterator<Edge> outEdges = rootVertex.edges(Direction.OUT, edgeType.getProperty());
1331         while (outEdges.hasNext()) {
1332             final Edge edge = outEdges.next();
1333             final Vertex vertexIn = edge.inVertex();
1334             final Iterator<Edge> outSubEdges = vertexIn.edges(Direction.OUT);
1335             while (outSubEdges.hasNext()) {
1336                 Edge subEdge = outSubEdges.next();
1337                 Vertex vertex = subEdge.inVertex();
1338                 Map<String, Object> properties = getProperties(vertex);
1339                 if (properties != null) {
1340                     String label = (String) properties.get(GraphPropertiesDictionary.LABEL.getProperty());
1341                     if (label.equals("property")) {
1342                         vertex.remove();
1343                     }
1344                 }
1345             }
1346             Map<String, Object> properties = getProperties(vertexIn);
1347             if (properties != null) {
1348                 String label = (String) properties.get(GraphPropertiesDictionary.LABEL.getProperty());
1349                 GraphNode node = GraphElementFactory
1350                     .createElement(label, GraphElementTypeEnum.Node, properties, GraphNode.class);
1351                 if (node != null) {
1352                     vertexIn.remove();
1353                 }
1354             }
1355         }
1356         return JanusGraphOperationStatus.OK;
1357     }
1358
1359     /**
1360      * Gets the JanusGraph instance.
1361      *
1362      * @return the JanusGraph instance
1363      * @throws JanusGraphException when the graph was not created
1364      */
1365     public JanusGraph getJanusGraph() {
1366         final Either<JanusGraph, JanusGraphOperationStatus> graphRes = janusGraphClient.getGraph();
1367         if (graphRes.isRight()) {
1368             final var errorMsg = String.format("Failed to retrieve graph. Status was '%s'", graphRes.right().value());
1369             log.error(EcompLoggerErrorCode.SCHEMA_ERROR, JanusGraphGenericDao.class.getName(), errorMsg);
1370             throw new JanusGraphException(graphRes.right().value(), errorMsg);
1371         }
1372         return graphRes.left().value();
1373     }
1374
1375     public Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> getChildrenVertecies(String key, String uniqueId,
1376                                                                                                                GraphEdgeLabels edgeType) {
1377         List<ImmutablePair<JanusGraphVertex, Edge>> immutablePairs = new ArrayList<>();
1378         Either<JanusGraph, JanusGraphOperationStatus> graphRes = janusGraphClient.getGraph();
1379         if (graphRes.isRight()) {
1380             log.error("Failed to retrieve graph. status is {}", graphRes);
1381             return Either.right(graphRes.right().value());
1382         }
1383         JanusGraph janusGraph = graphRes.left().value();
1384         @SuppressWarnings("unchecked") Iterable<JanusGraphVertex> vertices = janusGraph.query().has(key, uniqueId).vertices();
1385         if (vertices == null || !vertices.iterator().hasNext()) {
1386             return Either.right(JanusGraphOperationStatus.INVALID_ID);
1387         }
1388         return getChildrenVerticies(vertices.iterator().next(), edgeType);
1389     }
1390     
1391     public Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> getChildrenVerticies(
1392             final JanusGraphVertex rootVertex, final GraphEdgeLabels edgeType) {
1393         return getEdgeVerticies(rootVertex, Direction.OUT, edgeType);
1394     }
1395         
1396     public Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> getParentVerticies(
1397             final JanusGraphVertex rootVertex, final GraphEdgeLabels edgeType) {
1398         return getEdgeVerticies(rootVertex, Direction.IN, edgeType);
1399     }
1400         
1401     public Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> getEdgeVerticies(
1402             final JanusGraphVertex rootVertex, final Direction direction, final GraphEdgeLabels edgeType) {
1403         final List<ImmutablePair<JanusGraphVertex, Edge>> immutablePairs = new ArrayList<>();
1404         final Iterator<Edge> edgesCreatorIterator = rootVertex.edges(direction, edgeType.getProperty());
1405         if (edgesCreatorIterator != null) {
1406             while (edgesCreatorIterator.hasNext()) {
1407                 Edge edge = edgesCreatorIterator.next();
1408                 JanusGraphVertex vertex = Direction.OUT.equals(direction)? (JanusGraphVertex) edge.inVertex() : (JanusGraphVertex) edge.outVertex();
1409                 ImmutablePair<JanusGraphVertex, Edge> immutablePair = new ImmutablePair<>(vertex, edge);
1410                 immutablePairs.add(immutablePair);
1411             }
1412         }
1413         if (immutablePairs.isEmpty()) {
1414             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1415         }
1416         return Either.left(immutablePairs);
1417     }
1418
1419     public <T extends GraphNode> Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> getChildrenNodes(String key, String uniqueId,
1420                                                                                                                        GraphEdgeLabels edgeType,
1421                                                                                                                        NodeTypeEnum nodeTypeEnum,
1422                                                                                                                        Class<T> clazz) {
1423         return this.getChildrenNodes(key, uniqueId, edgeType, nodeTypeEnum, clazz, true);
1424     }
1425
1426     private JanusGraphOperationStatus checkLockError(String lockId, Either<GraphNodeLock, JanusGraphOperationStatus> lockNodeNew) {
1427         JanusGraphOperationStatus status;
1428         JanusGraphOperationStatus error = lockNodeNew.right().value();
1429         log.debug("Failed to Lock node for {}  error = {}", lockId, error);
1430         if (error.equals(JanusGraphOperationStatus.JANUSGRAPH_SCHEMA_VIOLATION) || error.equals(JanusGraphOperationStatus.ILLEGAL_ARGUMENT)) {
1431             status = JanusGraphOperationStatus.ALREADY_LOCKED;
1432         } else {
1433             status = error;
1434         }
1435         return status;
1436     }
1437
1438     /**
1439      * @param node
1440      * @return
1441      */
1442     public JanusGraphOperationStatus releaseElement(GraphNode node) {
1443         String lockId = createLockElementId(node);
1444         return unlockNode(lockId);
1445     }
1446
1447     private JanusGraphOperationStatus unlockNode(String lockId) {
1448         GraphNodeLock lockNode = new GraphNodeLock(lockId.toString());
1449         Either<GraphNodeLock, JanusGraphOperationStatus> lockNodeNew = deleteNode(lockNode, GraphNodeLock.class);
1450         if (lockNodeNew.isLeft()) {
1451             log.debug("Lock node released for lock id = {}", lockId);
1452             return janusGraphClient.commit();
1453         } else {
1454             janusGraphClient.rollback();
1455             JanusGraphOperationStatus error = lockNodeNew.right().value();
1456             log.debug("Failed to Release node for lock id {} error = {}", lockId, error);
1457             return error;
1458         }
1459     }
1460
1461     public JanusGraphOperationStatus releaseElement(String id, NodeTypeEnum type) {
1462         StringBuilder lockId = new StringBuilder(LOCK_NODE_PREFIX);
1463         lockId.append(type.getName()).append("_").append(id);
1464         return unlockNode(lockId.toString());
1465     }
1466
1467     private String createLockElementId(GraphNode node) {
1468         StringBuilder lockId = new StringBuilder(LOCK_NODE_PREFIX);
1469         lockId.append(node.getLabel()).append("_").append(node.getUniqueId());
1470         return lockId.toString();
1471     }
1472
1473     public <T extends GraphNode> Either<ImmutablePair<T, GraphEdge>, JanusGraphOperationStatus> getChild(String key, String uniqueId,
1474                                                                                                          GraphEdgeLabels edgeType,
1475                                                                                                          NodeTypeEnum nodeTypeEnum, Class<T> clazz) {
1476         Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> childrenNodes = getChildrenNodes(key, uniqueId, edgeType, nodeTypeEnum,
1477             clazz);
1478         if (childrenNodes.isRight()) {
1479             return Either.right(childrenNodes.right().value());
1480         }
1481         List<ImmutablePair<T, GraphEdge>> value = childrenNodes.left().value();
1482         if (value.size() > 1) {
1483             return Either.right(JanusGraphOperationStatus.MULTIPLE_CHILDS_WITH_SAME_EDGE);
1484         }
1485         return Either.left(value.get(0));
1486     }
1487
1488     public ImmutablePair<JanusGraphVertex, Edge> getChildVertex(JanusGraphVertex vertex, GraphEdgeLabels edgeType) {
1489         ImmutablePair<JanusGraphVertex, Edge> pair = null;
1490         Iterator<Edge> edges = vertex.edges(Direction.OUT, edgeType.getProperty());
1491         if (edges.hasNext()) {
1492             // get only first edge
1493             Edge edge = edges.next();
1494             pair = new ImmutablePair<>((JanusGraphVertex) edge.inVertex(), edge);
1495         }
1496         return pair;
1497     }
1498
1499     public <T extends GraphNode> Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> getParentNodes(String key, String uniqueId,
1500                                                                                                                      GraphEdgeLabels edgeType,
1501                                                                                                                      NodeTypeEnum nodeTypeEnum,
1502                                                                                                                      Class<T> clazz) {
1503         List<ImmutablePair<T, GraphEdge>> immutablePairs = new ArrayList<>();
1504         T data = null;
1505         GraphEdge graphEdge = null;
1506         Either<JanusGraph, JanusGraphOperationStatus> graphRes = janusGraphClient.getGraph();
1507         if (graphRes.isRight()) {
1508             log.error("Failed to retrieve graph. status is {}", graphRes);
1509             return Either.right(graphRes.right().value());
1510         }
1511         JanusGraph janusGraph = graphRes.left().value();
1512         @SuppressWarnings("unchecked") Iterable<JanusGraphVertex> vertices = janusGraph.query().has(key, uniqueId).vertices();
1513         if (vertices == null || !vertices.iterator().hasNext()) {
1514             return Either.right(JanusGraphOperationStatus.INVALID_ID);
1515         }
1516         Vertex rootVertex = vertices.iterator().next();
1517         Iterator<Edge> edgesCreatorIterator = rootVertex.edges(Direction.IN, edgeType.name());
1518         if (edgesCreatorIterator != null) {
1519             while (edgesCreatorIterator.hasNext()) {
1520                 Edge edge = edgesCreatorIterator.next();
1521                 Map<String, Object> edgeProps = getProperties(edge);
1522                 GraphEdgeLabels edgeTypeFromGraph = GraphEdgeLabels.getByName(edge.label());
1523                 graphEdge = new GraphEdge(edgeTypeFromGraph, edgeProps);
1524                 Vertex outgoingVertex = edge.outVertex();
1525                 Map<String, Object> properties = getProperties(outgoingVertex);
1526                 data = GraphElementFactory.createElement(nodeTypeEnum.getName(), GraphElementTypeEnum.Node, properties, clazz);
1527                 ImmutablePair<T, GraphEdge> immutablePair = new ImmutablePair<>(clazz.cast(data), graphEdge);
1528                 immutablePairs.add(immutablePair);
1529             }
1530         }
1531         if (immutablePairs.isEmpty()) {
1532             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1533         }
1534         return Either.left(immutablePairs);
1535     }
1536
1537     public <T extends GraphNode> Either<ImmutablePair<T, GraphEdge>, JanusGraphOperationStatus> getParentNode(String key, String uniqueId,
1538                                                                                                               GraphEdgeLabels edgeType,
1539                                                                                                               NodeTypeEnum nodeTypeEnum,
1540                                                                                                               Class<T> clazz) {
1541         Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> parentNodesRes = this
1542             .getParentNodes(key, uniqueId, edgeType, nodeTypeEnum, clazz);
1543         if (parentNodesRes.isRight()) {
1544             log.debug("failed to get edge key:{} uniqueId:{} edgeType {} nodeTypeEnum: {}, reason:{}", key, uniqueId, edgeType, nodeTypeEnum,
1545                 parentNodesRes.right().value());
1546             return Either.right(parentNodesRes.right().value());
1547         }
1548         List<ImmutablePair<T, GraphEdge>> value = parentNodesRes.left().value();
1549         if (value.size() > 1) {
1550             return Either.right(JanusGraphOperationStatus.MULTIPLE_CHILDS_WITH_SAME_EDGE);
1551         }
1552         return Either.left(value.get(0));
1553     }
1554
1555     public <T extends GraphNode> Either<ImmutablePair<T, GraphEdge>, JanusGraphOperationStatus> getChildByEdgeCriteria(String key, String uniqueId,
1556                                                                                                                        GraphEdgeLabels edgeType,
1557                                                                                                                        NodeTypeEnum nodeTypeEnum,
1558                                                                                                                        Class<T> clazz,
1559                                                                                                                        Map<String, Object> edgeProperties) {
1560         Either<Edge, JanusGraphOperationStatus> outgoingEdgeByCriteria = getOutgoingEdgeByCriteria(key, uniqueId, edgeType, edgeProperties);
1561         if (outgoingEdgeByCriteria.isRight()) {
1562             JanusGraphOperationStatus status = outgoingEdgeByCriteria.right().value();
1563             log.debug("Cannot find outgoing edge from vertex {} with label {} and properties {}" + uniqueId, edgeType, edgeProperties);
1564             return Either.right(status);
1565         }
1566         Edge edge = outgoingEdgeByCriteria.left().value();
1567         Map<String, Object> edgeProps = getProperties(edge);
1568         GraphEdgeLabels edgeTypeFromGraph = GraphEdgeLabels.getByName(edge.label());
1569         GraphEdge graphEdge = new GraphEdge(edgeTypeFromGraph, edgeProps);
1570         Vertex outgoingVertex = edge.inVertex();
1571         Map<String, Object> properties = getProperties(outgoingVertex);
1572         T data = GraphElementFactory.createElement(nodeTypeEnum.getName(), GraphElementTypeEnum.Node, properties, clazz);
1573         ImmutablePair<T, GraphEdge> immutablePair = new ImmutablePair<>(clazz.cast(data), graphEdge);
1574         return Either.left(immutablePair);
1575     }
1576
1577     public Either<ImmutablePair<JanusGraphVertex, Edge>, JanusGraphOperationStatus> getChildByEdgeCriteria(JanusGraphVertex vertex,
1578                                                                                                            GraphEdgeLabels edgeType,
1579                                                                                                            Map<String, Object> edgeProperties) {
1580         Either<Edge, JanusGraphOperationStatus> outgoingEdgeByCriteria = getOutgoingEdgeByCriteria(vertex, edgeType, edgeProperties);
1581         if (outgoingEdgeByCriteria.isRight()) {
1582             JanusGraphOperationStatus status = outgoingEdgeByCriteria.right().value();
1583             log.debug("Cannot find outgoing edge from vertex {} with label {} and properties {}", vertex, edgeType, edgeProperties);
1584             return Either.right(status);
1585         }
1586         Edge edge = outgoingEdgeByCriteria.left().value();
1587         JanusGraphVertex outgoingVertex = (JanusGraphVertex) edge.inVertex();
1588         ImmutablePair<JanusGraphVertex, Edge> immutablePair = new ImmutablePair<>(outgoingVertex, edge);
1589         return Either.left(immutablePair);
1590     }
1591
1592     public Either<Edge, JanusGraphOperationStatus> getOutgoingEdgeByCriteria(String key, String value, GraphEdgeLabels label,
1593                                                                              Map<String, Object> props) {
1594         Either<JanusGraphVertex, JanusGraphOperationStatus> vertexFrom = getVertexByProperty(key, value);
1595         if (vertexFrom.isRight()) {
1596             JanusGraphOperationStatus status = vertexFrom.right().value();
1597             if (status == JanusGraphOperationStatus.NOT_FOUND) {
1598                 return Either.right(JanusGraphOperationStatus.INVALID_ID);
1599             }
1600             return Either.right(status);
1601         }
1602         return getOutgoingEdgeByCriteria(vertexFrom.left().value(), label, props);
1603     }
1604
1605     public Either<Edge, JanusGraphOperationStatus> getOutgoingEdgeByCriteria(JanusGraphVertex vertex, GraphEdgeLabels label,
1606                                                                              Map<String, Object> props) {
1607         JanusGraphVertexQuery<?> query = vertex.query();
1608         query = query.direction(Direction.OUT).labels(label.getProperty());
1609         if (props != null && !props.isEmpty()) {
1610             for (Map.Entry<String, Object> entry : props.entrySet()) {
1611                 query = query.has(entry.getKey(), entry.getValue());
1612             }
1613         }
1614         Edge matchingEdge = null;
1615         Iterable<JanusGraphEdge> edges = query.edges();
1616         if (edges == null) {
1617             log.debug("No edges in graph for criteria");
1618             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1619         }
1620         Iterator<JanusGraphEdge> eIter = edges.iterator();
1621         if (eIter.hasNext()) {
1622             matchingEdge = eIter.next();
1623         }
1624         if (matchingEdge == null) {
1625             log.debug("No edges in graph for criteria");
1626             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1627         }
1628         return Either.left(matchingEdge);
1629     }
1630
1631     public <T extends GraphNode> Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> deleteChildrenNodes(String key, String uniqueId,
1632                                                                                                                           GraphEdgeLabels edgeType,
1633                                                                                                                           NodeTypeEnum nodeTypeEnum,
1634                                                                                                                           Class<T> clazz) {
1635         List<ImmutablePair<T, GraphEdge>> result = new ArrayList<>();
1636         Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> childrenNodesRes = getChildrenNodes(key, uniqueId, edgeType,
1637             nodeTypeEnum, clazz);
1638         if (childrenNodesRes.isRight()) {
1639             JanusGraphOperationStatus status = childrenNodesRes.right().value();
1640             return Either.right(status);
1641         }
1642         List<ImmutablePair<T, GraphEdge>> list = childrenNodesRes.left().value();
1643         for (ImmutablePair<T, GraphEdge> pair : list) {
1644             T node = pair.getKey();
1645             Either<T, JanusGraphOperationStatus> deleteNodeRes = this.deleteNode(node, clazz);
1646             if (deleteNodeRes.isRight()) {
1647                 JanusGraphOperationStatus status = deleteNodeRes.right().value();
1648                 log.error("Failed to delete node {} . status is {}", node, status);
1649                 return Either.right(status);
1650             }
1651             ImmutablePair<T, GraphEdge> deletedPair = new ImmutablePair<>(node, pair.getValue());
1652             result.add(deletedPair);
1653         }
1654         return Either.left(result);
1655     }
1656
1657     public void setProperties(Element element, Map<String, Object> properties) {
1658         if (properties != null && !properties.isEmpty()) {
1659             Object[] propertyKeyValues = new Object[properties.size() * 2];
1660             int i = 0;
1661             for (Entry<String, Object> entry : properties.entrySet()) {
1662                 propertyKeyValues[i++] = entry.getKey();
1663                 propertyKeyValues[i++] = entry.getValue();
1664             }
1665             ElementHelper.attachProperties(element, propertyKeyValues);
1666         }
1667     }
1668
1669     public Map<String, Object> getProperties(Element element) {
1670         Map<String, Object> result = new HashMap<>();
1671         if (element != null && element.keys() != null && element.keys().size() > 0) {
1672             Map<String, Property> propertyMap = ElementHelper.propertyMap(element, element.keys().toArray(new String[element.keys().size()]));
1673             for (Entry<String, Property> entry : propertyMap.entrySet()) {
1674                 String key = entry.getKey();
1675                 Object value = entry.getValue().value();
1676                 result.put(key, value);
1677             }
1678         }
1679         return result;
1680     }
1681
1682     public Object getProperty(JanusGraphVertex vertex, String key) {
1683         PropertyKey propertyKey = janusGraphClient.getGraph().left().value().getPropertyKey(key);
1684         return vertex.valueOrNull(propertyKey);
1685     }
1686
1687     public Object getProperty(Edge edge, String key) {
1688         Object value = null;
1689         Property<Object> property = edge.property(key);
1690         if (property != null) {
1691             return property.orElse(null);
1692         }
1693         return value;
1694     }
1695
1696     public <T extends GraphNode> Either<List<ImmutablePair<T, GraphEdge>>, JanusGraphOperationStatus> getChildrenByEdgeCriteria(Vertex vertex,
1697                                                                                                                                 String vertexUniqueId,
1698                                                                                                                                 GraphEdgeLabels edgeType,
1699                                                                                                                                 NodeTypeEnum nodeTypeEnum,
1700                                                                                                                                 Class<T> clazz,
1701                                                                                                                                 Map<String, Object> edgeProperties) {
1702         List<ImmutablePair<T, GraphEdge>> result = new ArrayList<>();
1703         Either<List<Edge>, JanusGraphOperationStatus> outgoingEdgeByCriteria = getOutgoingEdgesByCriteria(vertex, edgeType, edgeProperties);
1704         if (outgoingEdgeByCriteria.isRight()) {
1705             JanusGraphOperationStatus status = outgoingEdgeByCriteria.right().value();
1706             log.debug("Cannot find outgoing edge from vertex {} with label {}  and properties {}", vertexUniqueId, edgeType, edgeProperties);
1707             return Either.right(status);
1708         }
1709         List<Edge> edges = outgoingEdgeByCriteria.left().value();
1710         if (edges != null) {
1711             for (Edge edge : edges) {
1712                 Map<String, Object> edgeProps = getProperties(edge);
1713                 GraphEdgeLabels edgeTypeFromGraph = GraphEdgeLabels.getByName(edge.label());
1714                 GraphEdge graphEdge = new GraphEdge(edgeTypeFromGraph, edgeProps);
1715                 Vertex outgoingVertex = edge.inVertex();
1716                 Map<String, Object> properties = getProperties(outgoingVertex);
1717                 T data = GraphElementFactory.createElement(nodeTypeEnum.getName(), GraphElementTypeEnum.Node, properties, clazz);
1718                 ImmutablePair<T, GraphEdge> immutablePair = new ImmutablePair<>(clazz.cast(data), graphEdge);
1719                 result.add(immutablePair);
1720             }
1721         }
1722         return Either.left(result);
1723     }
1724
1725     public @NotNull
1726     Either<List<Edge>, JanusGraphOperationStatus> getOutgoingEdgesByCriteria(Vertex vertexFrom, GraphEdgeLabels label, Map<String, Object> props) {
1727         List<Edge> edgesResult = new ArrayList<>();
1728         JanusGraphVertex janusGraphVertex = (JanusGraphVertex) vertexFrom;
1729         JanusGraphVertexQuery<?> query = janusGraphVertex.query();
1730         query = query.direction(Direction.OUT).labels(label.getProperty());
1731         if (props != null && !props.isEmpty()) {
1732             for (Map.Entry<String, Object> entry : props.entrySet()) {
1733                 query = query.has(entry.getKey(), entry.getValue());
1734             }
1735         }
1736         Iterable<JanusGraphEdge> edges = query.edges();
1737         Iterator<JanusGraphEdge> eIter = edges.iterator();
1738         if (!eIter.hasNext()) {
1739             log.debug("No edges found in graph for criteria (label = {} properties={})", label.getProperty(), props);
1740             return Either.left(edgesResult);
1741         }
1742         while (eIter.hasNext()) {
1743             Edge edge = eIter.next();
1744             edgesResult.add(edge);
1745         }
1746         if (edgesResult.isEmpty()) {
1747             log.debug("No edges found in graph for criteria (label = {} properties={})", label.getProperty(), props);
1748             return Either.right(JanusGraphOperationStatus.NOT_FOUND);
1749         }
1750         return Either.left(edgesResult);
1751     }
1752 }