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