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