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