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