X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=aai-core%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Faai%2Fquery%2Fbuilder%2FGraphTraversalBuilder.java;h=c5c4512e98209515338c2af5bf15c2c7572181b0;hb=d749a1072e23073e320ffe78c3f0576da0486279;hp=bf9dd17ff544f47f7c60cba2c65ec8ebbd24b655;hpb=ec86dc93ea46f33d737b01124546884f7048390a;p=aai%2Faai-common.git diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java b/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java index bf9dd17f..c5c4512e 100644 --- a/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java +++ b/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java @@ -4,6 +4,8 @@ * ================================================================================ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. * ================================================================================ + * * Modifications Copyright © 2024 DEUTSCHE TELEKOM AG. + * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -17,10 +19,22 @@ * limitations under the License. * ============LICENSE_END========================================================= */ + package org.onap.aai.query.builder; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.Traversal; import org.apache.tinkerpop.gremlin.process.traversal.Traversal.Admin; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; @@ -32,106 +46,146 @@ import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.edges.EdgeRule; +import org.onap.aai.edges.EdgeRuleQuery; +import org.onap.aai.edges.enums.EdgeType; +import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; import org.onap.aai.schema.enums.ObjectMetadata; import org.onap.aai.schema.enums.PropertyMetadata; -import org.onap.aai.edges.EdgeRule; -import org.onap.aai.edges.EdgeRuleQuery; -import org.onap.aai.edges.enums.EdgeType; -import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException; -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; - -import java.util.*; - /** * The Class GraphTraversalBuilder. */ public abstract class GraphTraversalBuilder extends QueryBuilder { - protected GraphTraversal traversal = null; - protected Admin completeTraversal = null; + protected GraphTraversal traversal = null; + protected Admin completeTraversal = null; - /** - * Instantiates a new graph traversal builder. - * - * @param loader the loader - */ - public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) { - super(loader, source); + protected QueryBuilder containerQuery; + protected QueryBuilder parentQuery; - traversal = (GraphTraversal) __.start(); + /** + * Instantiates a new graph traversal builder. + * + * @param loader the loader + */ + public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) { + super(loader, source); + traversal = (GraphTraversal) __.start(); - } + } - /** - * Instantiates a new graph traversal builder. - * - * @param loader the loader - * @param start the start - */ - public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) { - super(loader, source, start); + public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, GraphTraversal traversal) { + super(loader, source); + this.traversal = traversal; - traversal = (GraphTraversal) __.__(start); + } - } + /** + * Instantiates a new graph traversal builder. + * + * @param loader the loader + * @param start the start + */ + public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getVerticesByProperty(String key, Object value) { + traversal = (GraphTraversal) __.__(start); - // correct value call because the index is registered as an Integer - traversal.has(key, this.correctObjectType(value)); + } - stepIndex++; - return (QueryBuilder) this; - } + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByProperty(String key, Object value) { - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getVerticesByProperty(final String key, final List values) { + // correct value call because the index is registered as an Integer + this.vertexHas(key, this.correctObjectType(value)); + stepIndex++; + return (QueryBuilder) this; + } - //this is because the index is registered as an Integer - List correctedValues = new ArrayList<>(); - for (Object item : values) { - correctedValues.add(this.correctObjectType(item)); - } + @Override + protected void vertexHas(String key, Object value) { + traversal.has(key, value); + } - traversal.has(key, P.within(correctedValues)); + @Override + protected void vertexHasNot(String key) { + traversal.hasNot(key); + } - stepIndex++; - return (QueryBuilder) this; - } + @Override + protected void vertexHas(String key) { + traversal.has(key); + } - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getVerticesStartsWithProperty(String key, Object value) { + // TODO: Remove this once we test this - at this point i dont thib this is required + // because predicare is an object + /* + * @Override + * protected void vertexHas(final String key, final P predicate) { + * traversal.has(key, predicate); + * } + */ - // correct value call because the index is registered as an Integer - traversal.has(key, org.janusgraph.core.attribute.Text.textPrefix(value)); + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByProperty(final String key, final List values) { - stepIndex++; - return (QueryBuilder) this; - } + // this is because the index is registered as an Integer + List correctedValues = new ArrayList<>(); + for (Object item : values) { + correctedValues.add(this.correctObjectType(item)); + } + + this.vertexHas(key, P.within(correctedValues)); + stepIndex++; + return (QueryBuilder) this; + } + + /** + * @{inheritDoc} + */ + public QueryBuilder getVerticesByCommaSeperatedValue(String key, String value) { + ArrayList values = new ArrayList<>(Arrays.asList(value.split(","))); + int size = values.size(); + for (int i = 0; i < size; i++) { + values.set(i, values.get(i).trim()); + } + this.vertexHas(key, P.within(values)); + + stepIndex++; + return (QueryBuilder) this; + } /** * @{inheritDoc} */ @Override - public QueryBuilder getVerticesByProperty(String key) { + public QueryBuilder getVerticesStartsWithProperty(String key, Object value) { + + // correct value call because the index is registered as an Integer + // TODO Check if this needs to be in QB and add these as internal + this.vertexHas(key, org.janusgraph.core.attribute.Text.textPrefix(value)); - traversal.has(key); + stepIndex++; + return (QueryBuilder) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesByProperty(String key) { + this.vertexHas(key); stepIndex++; return (QueryBuilder) this; } @@ -141,759 +195,774 @@ public abstract class GraphTraversalBuilder extends QueryBuilder { */ @Override public QueryBuilder getVerticesExcludeByProperty(String key) { + this.vertexHasNot(key); + stepIndex++; + return (QueryBuilder) this; + } - traversal.hasNot(key); + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesExcludeByProperty(String key, Object value) { + + // correct value call because the index is registered as an Integer + this.vertexHas(key, P.neq(this.correctObjectType(value))); stepIndex++; return (QueryBuilder) this; } + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getVerticesExcludeByProperty(final String key, final List values) { - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getVerticesExcludeByProperty(String key, Object value) { + // this is because the index is registered as an Integer + List correctedValues = new ArrayList<>(); + for (Object item : values) { + correctedValues.add(this.correctObjectType(item)); + } - // correct value call because the index is registered as an Integer - traversal.has(key, P.neq(this.correctObjectType(value))); + this.vertexHas(key, P.without(correctedValues)); + stepIndex++; + return (QueryBuilder) this; + } - stepIndex++; - return (QueryBuilder) this; - } + @Override + public QueryBuilder getVerticesGreaterThanProperty(final String key, Object value) { + this.vertexHas(key, P.gte(this.correctObjectType(value))); - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getVerticesExcludeByProperty(final String key, final List values) { + stepIndex++; + return (QueryBuilder) this; + } - //this is because the index is registered as an Integer - List correctedValues = new ArrayList<>(); - for (Object item : values) { - correctedValues.add(this.correctObjectType(item)); - } + @Override + public QueryBuilder getVerticesLessThanProperty(final String key, Object value) { + this.vertexHas(key, P.lte(this.correctObjectType(value))); - traversal.has(key, P.without(correctedValues)); + stepIndex++; + return (QueryBuilder) this; + } - stepIndex++; - return (QueryBuilder) this; - } + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) { + traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType); + stepIndex++; + return (QueryBuilder) this; + } + /** + * @{inheritDoc} + */ @Override - public QueryBuilder getVerticesGreaterThanProperty(final String key, Object value) { + public QueryBuilder getTypedVerticesByMap(String type, Map map) { + + for (Map.Entry es : map.entrySet()) { + this.vertexHas(es.getKey(), es.getValue()); + stepIndex++; + } + traversal.has(AAIProperties.NODE_TYPE, type); + stepIndex++; + return (QueryBuilder) this; + } + + @Override + public QueryBuilder getVerticesByBooleanProperty(String key, Object value) { + + if (value != null && !"".equals(value)) { + boolean bValue = false; + + if (value instanceof String) {// "true" + bValue = Boolean.valueOf(value.toString()); + } else if (value instanceof Boolean) {// true + bValue = (Boolean) value; + } + + this.vertexHas(key, bValue); + stepIndex++; + } + return (QueryBuilder) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder createKeyQuery(Introspector obj) { + Set keys = obj.getKeys(); + Object val; + for (String key : keys) { + val = obj.getValue(key); + Optional metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS); + if (metadata.isPresent()) { + // use the db name for the field rather than the object model + key = metadata.get(); + } + if (val != null) { + // this is because the index is registered as an Integer + if (val.getClass().equals(Long.class)) { + this.vertexHas(key, Integer.valueOf(val.toString())); + } else { + this.vertexHas(key, val); + } + stepIndex++; + } + } + return (QueryBuilder) this; + } - traversal.has(key, P.gte(this.correctObjectType(value))); + @Override + public QueryBuilder exactMatchQuery(Introspector obj) { + this.createKeyQuery(obj); + allPropertiesQuery(obj); + this.createContainerQuery(obj); + return (QueryBuilder) this; + } + private void allPropertiesQuery(Introspector obj) { + Set props = obj.getProperties(); + Set keys = obj.getKeys(); + Object val; + for (String prop : props) { + if (obj.isSimpleType(prop) && !keys.contains(prop)) { + val = obj.getValue(prop); + if (val != null) { + Optional metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS); + if (metadata.isPresent()) { + // use the db name for the field rather than the object model + prop = metadata.get(); + } + // this is because the index is registered as an Integer + if (val.getClass().equals(Long.class)) { + this.vertexHas(prop, Integer.valueOf(val.toString())); + } else { + this.vertexHas(prop, val); + } + stepIndex++; + } + } + } + } + + @Override + public QueryBuilder createContainerQuery(Introspector obj) { + String type = obj.getChildDBName(); + String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT); + if (abstractType != null) { + String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(","); + traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors)); + } else { + traversal.has(AAIProperties.NODE_TYPE, type); + } stepIndex++; + markContainer(); return (QueryBuilder) this; } + /** + * @throws NoEdgeRuleFoundException + * @throws AAIException + * @{inheritDoc} + */ @Override - public QueryBuilder getVerticesLessThanProperty(final String key, Object value) { + public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) + throws AAIException { + createTraversal(type, parent, child, false); + return (QueryBuilder) this; + + } + + @Override + public QueryBuilder createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) + throws AAIException { + this.createTraversal(type, parent, child, true); + return (QueryBuilder) this; + } + + private void createTraversal(EdgeType type, Introspector parent, Introspector child, boolean isPrivateEdge) + throws AAIException { + String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT); + if ("true".equals(isAbstractType)) { + markParentBoundary(); + traversal.union(handleAbstractEdge(type, parent, child, isPrivateEdge)); + stepIndex++; + } else { + this.edgeQueryToVertex(type, parent, child, null); + } + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, + List labels) throws AAIException { + this.edgeQueryToVertex(type, out, in, labels); + return (QueryBuilder) this; + } + + private Traversal[] handleAbstractEdge(EdgeType type, Introspector abstractParent, + Introspector child, boolean isPrivateEdge) throws AAIException { + String childName = child.getDbName(); + String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS); + String[] inheritors = inheritorMetadata.split(","); + List> unionTraversals = new ArrayList<>(inheritors.length); + + for (int i = 0; i < inheritors.length; i++) { + String inheritor = inheritors[i]; + EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(inheritor, childName); + if (edgeRules.hasRule(qB.build())) { + Multimap rules = ArrayListMultimap.create(); + try { + rules = edgeRules.getRules(qB.edgeType(type).build()); + } catch (EdgeRuleNotFoundException e) { + throw new NoEdgeRuleFoundException(e); + } + + GraphTraversal innerTraversal = __.start(); + + final List inLabels = new ArrayList<>(); + final List outLabels = new ArrayList<>(); + + rules.values().forEach(rule -> { + if (rule.getDirection().equals(Direction.IN)) { + inLabels.add(rule.getLabel()); + } else { + outLabels.add(rule.getLabel()); + } + }); + + if (inLabels.isEmpty() && !outLabels.isEmpty()) { + innerTraversal.out(outLabels.toArray(new String[outLabels.size()])); + } else if (outLabels.isEmpty() && !inLabels.isEmpty()) { + innerTraversal.in(inLabels.toArray(new String[inLabels.size()])); + } else { + innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), + __.in(inLabels.toArray(new String[inLabels.size()]))); + } + + innerTraversal.has(AAIProperties.NODE_TYPE, childName); + unionTraversals.add(innerTraversal); + } + } + + return unionTraversals.toArray(new Traversal[unionTraversals.size()]); + } + + public QueryBuilder getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, + List labels) throws AAIException { + Introspector outObj = loader.introspectorFromName(outNodeType); + Introspector inObj = loader.introspectorFromName(inNodeType); + this.edgeQuery(type, outObj, inObj, labels); + + return (QueryBuilder) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder union(QueryBuilder... builder) { + GraphTraversal[] traversals = new GraphTraversal[builder.length]; + for (int i = 0; i < builder.length; i++) { + traversals[i] = (GraphTraversal) builder[i].getQuery(); + } + this.traversal.union(traversals); + stepIndex++; + + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder where(QueryBuilder... builder) { + for (int i = 0; i < builder.length; i++) { + this.traversal.where((GraphTraversal) builder[i].getQuery()); + stepIndex++; + } - traversal.has(key, P.lte(this.correctObjectType(value))); + return this; + } + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder or(QueryBuilder... builder) { + GraphTraversal[] traversals = new GraphTraversal[builder.length]; + for (int i = 0; i < builder.length; i++) { + traversals[i] = (GraphTraversal) builder[i].getQuery(); + } + this.traversal.or(traversals); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder store(String name) { + + this.traversal.store(name); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder cap(String name) { + this.traversal.cap(name); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder unfold() { + this.traversal.unfold(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder dedup() { + + this.traversal.dedup(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder emit() { + + this.traversal.emit(); + stepIndex++; + + return this; + + } + + @Override + public QueryBuilder repeat(QueryBuilder builder) { + + this.traversal.repeat((GraphTraversal) builder.getQuery()); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder until(QueryBuilder builder) { + this.traversal.until((GraphTraversal) builder.getQuery()); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder groupCount() { + this.traversal.groupCount(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder both() { + this.traversal.both(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder tree() { + + this.traversal.tree(); + stepIndex++; + + return (QueryBuilder) this; + } + + @Override + public QueryBuilder by(String name) { + this.traversal.by(name); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder valueMap() { + this.traversal.valueMap(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder valueMap(String... names) { + this.traversal.valueMap(names); + stepIndex++; + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public QueryBuilder simplePath() { + this.traversal.simplePath(); + stepIndex++; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public QueryBuilder path() { + this.traversal.path(); + stepIndex++; + return (QueryBuilder) this; + } + + @Override + public QueryBuilder outE() { + this.traversal.outE(); + stepIndex++; + return (QueryBuilder) this; + } + + @Override + public QueryBuilder inE() { + this.traversal.inE(); + stepIndex++; + return (QueryBuilder) this; + } + + @Override + public QueryBuilder outV() { + this.traversal.outV(); stepIndex++; return (QueryBuilder) this; } + @Override + public QueryBuilder inV() { + this.traversal.inV(); + stepIndex++; + return (QueryBuilder) this; + } + + @Override + public QueryBuilder as(String name) { + this.traversal.as(name); + + stepIndex++; + return this; + } + + @Override + public QueryBuilder not(QueryBuilder builder) { + this.traversal.not(builder.getQuery()); + + stepIndex++; + return this; + } + + @Override + public QueryBuilder select(String name) { + this.traversal.select(name); + + stepIndex++; + + return this; + } + + @Override + public QueryBuilder select(String... names) { + if (names.length == 1) { + this.traversal.select(names[0]); + } else if (names.length == 2) { + this.traversal.select(names[0], names[1]); + } else if (names.length > 2) { + String[] otherNames = Arrays.copyOfRange(names, 2, names.length); + this.traversal.select(names[0], names[1], otherNames); + } + + stepIndex++; + + return this; + } + + /** + * Edge query. + * + * @param outObj the out type + * @param inObj the in type + * @throws NoEdgeRuleFoundException + * @throws AAIException + */ + private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List labels) + throws AAIException { + String outType = outObj.getDbName(); + String inType = inObj.getDbName(); + + if (outObj.isContainer()) { + outType = outObj.getChildDBName(); + } + if (inObj.isContainer()) { + inType = inObj.getChildDBName(); + } + markParentBoundary(); + Multimap rules = ArrayListMultimap.create(); + EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type); + + if (labels == null) { + try { + rules.putAll(edgeRules.getRules(qB.build())); + } catch (EdgeRuleNotFoundException e) { + // is ok per original functioning of this section + // TODO add "best try" sort of flag to the EdgeRuleQuery + // to indicate if the exception should be thrown or not + } + } else { + for (String label : labels) { + try { + rules.putAll(edgeRules.getRules(qB.label(label).build())); + } catch (EdgeRuleNotFoundException e) { + throw new NoEdgeRuleFoundException(e); + } + } + if (rules.isEmpty()) { + throw new NoEdgeRuleFoundException( + "No edge rules found for " + outType + " and " + inType + " of type " + type.toString()); + } + } + + final List inLabels = new ArrayList<>(); + final List outLabels = new ArrayList<>(); + + for (EdgeRule rule : rules.values()) { + if (labels != null && !labels.contains(rule.getLabel())) { + return; + } else { + if (Direction.IN.equals(rule.getDirection())) { + inLabels.add(rule.getLabel()); + } else { + outLabels.add(rule.getLabel()); + } + } + } + + if (inLabels.isEmpty() && !outLabels.isEmpty()) { + traversal.out(outLabels.toArray(new String[outLabels.size()])); + } else if (outLabels.isEmpty() && !inLabels.isEmpty()) { + traversal.in(inLabels.toArray(new String[inLabels.size()])); + } else { + traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), + __.in(inLabels.toArray(new String[inLabels.size()]))); + } + + stepIndex++; + + this.createContainerQuery(inObj); + + } + + /** + * Edge query. + * + * @param outObj the out type + * @param inObj the in type + * @throws NoEdgeRuleFoundException + * @throws AAIException + */ + private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List labels) + throws AAIException { + String outType = outObj.getDbName(); + String inType = inObj.getDbName(); + + if (outObj.isContainer()) { + outType = outObj.getChildDBName(); + } + if (inObj.isContainer()) { + inType = inObj.getChildDBName(); + } + + markParentBoundary(); + Multimap rules = ArrayListMultimap.create(); + EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type); + + try { + if (labels == null) { + rules.putAll(edgeRules.getRules(qB.build())); + } else { + for (String label : labels) { + rules.putAll(edgeRules.getRules(qB.label(label).build())); + } + } + } catch (EdgeRuleNotFoundException e) { + throw new NoEdgeRuleFoundException(e); + } + + final List inLabels = new ArrayList<>(); + final List outLabels = new ArrayList<>(); + + for (EdgeRule rule : rules.values()) { + if (labels != null && !labels.contains(rule.getLabel())) { + return; + } else { + if (Direction.IN.equals(rule.getDirection())) { + inLabels.add(rule.getLabel()); + } else { + outLabels.add(rule.getLabel()); + } + } + } + + if (inLabels.isEmpty() && !outLabels.isEmpty()) { + traversal.outE(outLabels.toArray(new String[outLabels.size()])); + } else if (outLabels.isEmpty() && !inLabels.isEmpty()) { + traversal.inE(inLabels.toArray(new String[inLabels.size()])); + } else { + traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), + __.inE(inLabels.toArray(new String[inLabels.size()]))); + } + } + + @Override + public QueryBuilder limit(long amount) { + traversal.limit(amount); + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public E2 getQuery() { + return (E2) this.traversal; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder getParentQuery() { + return this.parentQuery != null + ? this.parentQuery + : cloneQueryAtStep(parentStepIndex); + } + + @Override + public QueryBuilder getContainerQuery() { + + if (this.parentStepIndex == 0) { + return removeQueryStepsBetween(0, containerStepIndex); + } else { + return this.containerQuery; + } + } + + /** + * @{inheritDoc} + */ + @Override + public void markParentBoundary() { + this.parentQuery = cloneQueryAtStep(stepIndex); + parentStepIndex = stepIndex; + } + + @Override + public void markContainer() { + this.containerQuery = cloneQueryAtStep(stepIndex); + containerStepIndex = stepIndex; + } + + /** + * @{inheritDoc} + */ + @Override + public Vertex getStart() { + return this.start; + } + + protected int getParentStepIndex() { + return parentStepIndex; + } + + protected int getContainerStepIndex() { + return containerStepIndex; + } + + protected int getStepIndex() { + return stepIndex; + } + + /** + * end is exclusive + * + * @param start + * @param end + * @return + */ + protected abstract QueryBuilder removeQueryStepsBetween(int start, int end); + + protected void executeQuery() { + + Admin admin; + if (start != null) { + this.completeTraversal = traversal.asAdmin(); + } else { + admin = source.V().asAdmin(); + TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin); + + this.completeTraversal = (Admin) admin; + + } + + } + + @Override + public boolean hasNext() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return this.completeTraversal.hasNext(); + } + + @Override + public E next() { + if (this.completeTraversal == null) { + executeQuery(); + } + + return this.completeTraversal.next(); + } + + @Override + public List toList() { + if (this.completeTraversal == null) { + executeQuery(); + } + return this.completeTraversal.toList(); + } + + protected QueryBuilder has(String key, String value) { + traversal.has(key, value); + + return (QueryBuilder) this; + } - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getChildVerticesFromParent(String parentKey, String parentValue, String childType) { - traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType); - stepIndex++; - return (QueryBuilder) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getTypedVerticesByMap(String type, Map map) { - - for (Map.Entry es : map.entrySet()) { - traversal.has(es.getKey(), es.getValue()); - stepIndex++; - } - traversal.has(AAIProperties.NODE_TYPE, type); - stepIndex++; - return (QueryBuilder) this; - } - - @Override - public QueryBuilder getVerticesByBooleanProperty(String key, Object value) { - - if(value!=null && !"".equals(value)) { - boolean bValue = false; - - if(value instanceof String){//"true" - bValue = Boolean.valueOf(value.toString()); - } else if(value instanceof Boolean){//true - bValue = (Boolean) value; - } - - traversal.has(key, bValue); - stepIndex++; - } - return (QueryBuilder) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder createKeyQuery(Introspector obj) { - Set keys = obj.getKeys(); - Object val; - for (String key : keys) { - val = obj.getValue(key); - Optional metadata = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS); - if (metadata.isPresent()) { - //use the db name for the field rather than the object model - key = metadata.get(); - } - if (val != null) { - //this is because the index is registered as an Integer - if (val.getClass().equals(Long.class)) { - traversal.has(key,new Integer(val.toString())); - } else { - traversal.has(key, val); - } - stepIndex++; - } - } - return (QueryBuilder) this; - } - - @Override - public QueryBuilder exactMatchQuery(Introspector obj) { - this.createKeyQuery(obj); - allPropertiesQuery(obj); - this.createContainerQuery(obj); - return (QueryBuilder) this; - } - - private void allPropertiesQuery(Introspector obj) { - Set props = obj.getProperties(); - Set keys = obj.getKeys(); - Object val; - for (String prop : props) { - if (obj.isSimpleType(prop) && !keys.contains(prop)) { - val = obj.getValue(prop); - if (val != null) { - Optional metadata = obj.getPropertyMetadata(prop, PropertyMetadata.DB_ALIAS); - if (metadata.isPresent()) { - //use the db name for the field rather than the object model - prop = metadata.get(); - } - //this is because the index is registered as an Integer - if (val.getClass().equals(Long.class)) { - traversal.has(prop,new Integer(val.toString())); - } else { - traversal.has(prop, val); - } - stepIndex++; - } - } - } - } - - /** - * @{inheritDoc} - */ - @Override - - public QueryBuilder createContainerQuery(Introspector obj) { - String type = obj.getChildDBName(); - String abstractType = obj.getMetadata(ObjectMetadata.ABSTRACT); - if (abstractType != null) { - String[] inheritors = obj.getMetadata(ObjectMetadata.INHERITORS).split(","); - traversal.has(AAIProperties.NODE_TYPE, P.within(inheritors)); - } else { - traversal.has(AAIProperties.NODE_TYPE, type); - } - stepIndex++; - markContainer(); - return (QueryBuilder) this; - } - - /** - * @throws NoEdgeRuleFoundException - * @throws AAIException - * @{inheritDoc} - */ - @Override - public QueryBuilder createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException { - createTraversal(type, parent, child, false); - return (QueryBuilder) this; - - } - - @Override - public QueryBuilder createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) throws AAIException { - this.createTraversal(type, parent, child, true); - return (QueryBuilder) this; - } - - private void createTraversal(EdgeType type, Introspector parent, Introspector child, boolean isPrivateEdge) throws AAIException { - String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT); - if ("true".equals(isAbstractType)) { - markParentBoundary(); - traversal.union(handleAbstractEdge(type, parent, child, isPrivateEdge)); - stepIndex++; - } else { - this.edgeQueryToVertex(type, parent, child, null); - } - } - - /** - * - * @{inheritDoc} - */ - @Override - public QueryBuilder createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List labels) throws AAIException { - this.edgeQueryToVertex(type, out, in, labels); - return (QueryBuilder) this; - } - - private Traversal[] handleAbstractEdge(EdgeType type, Introspector abstractParent, Introspector child, boolean isPrivateEdge) throws AAIException { - String childName = child.getDbName(); - String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS); - String[] inheritors = inheritorMetadata.split(","); - List> unionTraversals = new ArrayList<>(inheritors.length); - - for (int i = 0; i < inheritors.length; i++) { - String inheritor = inheritors[i]; - EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(inheritor, childName); - if (edgeRules.hasRule(qB.build())) { - Multimap rules = ArrayListMultimap.create(); - try { - rules = edgeRules.getRules(qB.edgeType(type).build()); - } catch (EdgeRuleNotFoundException e) { - throw new NoEdgeRuleFoundException(e); - } - - GraphTraversal innerTraversal = __.start(); - - final List inLabels = new ArrayList<>(); - final List outLabels = new ArrayList<>(); - - rules.values().forEach(rule -> { - if (rule.getDirection().equals(Direction.IN)) { - inLabels.add(rule.getLabel()); - } else { - outLabels.add(rule.getLabel()); - } - } ); - - if (inLabels.isEmpty() && !outLabels.isEmpty()) { - innerTraversal.out(outLabels.toArray(new String[outLabels.size()])); - } else if (outLabels.isEmpty() && !inLabels.isEmpty()) { - innerTraversal.in(inLabels.toArray(new String[inLabels.size()])); - } else { - innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()]))); - } - - innerTraversal.has(AAIProperties.NODE_TYPE, childName); - unionTraversals.add(innerTraversal); - } - } - - return unionTraversals.toArray(new Traversal[unionTraversals.size()]); - } - - public QueryBuilder getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, List labels) throws AAIException { - Introspector outObj = loader.introspectorFromName(outNodeType); - Introspector inObj = loader.introspectorFromName(inNodeType); - this.edgeQuery(type, outObj, inObj, labels); - - return (QueryBuilder)this; - } - - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder union(QueryBuilder... builder) { - GraphTraversal[] traversals = new GraphTraversal[builder.length]; - for (int i = 0; i < builder.length; i++) { - traversals[i] = (GraphTraversal)builder[i].getQuery(); - } - this.traversal.union(traversals); - stepIndex++; - - return this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder where(QueryBuilder... builder) { - for (int i = 0; i < builder.length; i++) { - this.traversal.where((GraphTraversal)builder[i].getQuery()); - stepIndex++; - } - - return this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder or(QueryBuilder... builder) { - GraphTraversal[] traversals = new GraphTraversal[builder.length]; - for (int i = 0; i < builder.length; i++) { - traversals[i] = (GraphTraversal)builder[i].getQuery(); - } - this.traversal.or(traversals); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder store(String name) { - - this.traversal.store(name); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder cap(String name) { - this.traversal.cap(name); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder unfold() { - this.traversal.unfold(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder dedup() { - - this.traversal.dedup(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder emit() { - - this.traversal.emit(); - stepIndex++; - - return this; - - } - - @Override - public QueryBuilder repeat(QueryBuilder builder) { - - this.traversal.repeat((GraphTraversal)builder.getQuery()); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder until(QueryBuilder builder) { - this.traversal.until((GraphTraversal)builder.getQuery()); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder groupCount() { - this.traversal.groupCount(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder both() { - this.traversal.both(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder tree() { - - this.traversal.tree(); - stepIndex++; - - return (QueryBuilder)this; - } - - @Override - public QueryBuilder by(String name) { - this.traversal.by(name); - stepIndex++; - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public QueryBuilder simplePath(){ - this.traversal.simplePath(); - stepIndex++; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public QueryBuilder path(){ - this.traversal.path(); - stepIndex++; - return (QueryBuilder)this; - } - - @Override - public QueryBuilder outE() { - this.traversal.outE(); - stepIndex++; - return (QueryBuilder)this; - } - - @Override - public QueryBuilder inE() { - this.traversal.inE(); - stepIndex++; - return (QueryBuilder)this; - } - - @Override - public QueryBuilder outV() { - this.traversal.outV(); - stepIndex++; - return (QueryBuilder)this; - } - - @Override - public QueryBuilder inV() { - this.traversal.inV(); - stepIndex++; - return (QueryBuilder)this; - } - - @Override - public QueryBuilder as(String name) { - this.traversal.as(name); - - stepIndex++; - return this; - } - - @Override - public QueryBuilder not(QueryBuilder builder) { - this.traversal.not(builder.getQuery()); - - stepIndex++; - return this; - } - - @Override - public QueryBuilder select(String name) { - this.traversal.select(name); - - stepIndex++; - - return this; - } - - @Override - public QueryBuilder select(String... names) { - if(names.length == 1) { - this.traversal.select(names[0]); - } - else if(names.length == 2) { - this.traversal.select(names[0], names[1]); - } - else if(names.length > 2){ - String[] otherNames = Arrays.copyOfRange(names, 2, names.length); - this.traversal.select(names[0], names[1], otherNames); - } - - stepIndex++; - - return this; - } - - /** - * Edge query. - * - * @param outObj the out type - * @param inObj the in type - * @throws NoEdgeRuleFoundException - * @throws AAIException - */ - private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List labels) throws AAIException { - String outType = outObj.getDbName(); - String inType = inObj.getDbName(); - - if (outObj.isContainer()) { - outType = outObj.getChildDBName(); - } - if (inObj.isContainer()) { - inType = inObj.getChildDBName(); - } - markParentBoundary(); - Multimap rules = ArrayListMultimap.create(); - EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type); - - if (labels == null) { - try { - rules.putAll(edgeRules.getRules(qB.build())); - } catch (EdgeRuleNotFoundException e) { - //is ok per original functioning of this section - //TODO add "best try" sort of flag to the EdgeRuleQuery - // to indicate if the exception should be thrown or not - } - } else { - for (String label : labels) { - try { - rules.putAll(edgeRules.getRules(qB.label(label).build())); - } catch (EdgeRuleNotFoundException e) { - throw new NoEdgeRuleFoundException(e); - } - } - if (rules.isEmpty()) { - throw new NoEdgeRuleFoundException("No edge rules found for " + outType + " and " + inType + " of type " + type.toString()); - } - } - - - final List inLabels = new ArrayList<>(); - final List outLabels = new ArrayList<>(); - - for (EdgeRule rule : rules.values()) { - if (labels != null && !labels.contains(rule.getLabel())) { - return; - } else { - if (Direction.IN.equals(rule.getDirection())) { - inLabels.add(rule.getLabel()); - } else { - outLabels.add(rule.getLabel()); - } - } - } - - if (inLabels.isEmpty() && !outLabels.isEmpty()) { - traversal.out(outLabels.toArray(new String[outLabels.size()])); - } else if (outLabels.isEmpty() && !inLabels.isEmpty()) { - traversal.in(inLabels.toArray(new String[inLabels.size()])); - } else { - traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), __.in(inLabels.toArray(new String[inLabels.size()]))); - } - - stepIndex++; - - this.createContainerQuery(inObj); - - } - - /** - * Edge query. - * - * @param outObj the out type - * @param inObj the in type - * @throws NoEdgeRuleFoundException - * @throws AAIException - */ - private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List labels) throws AAIException { - String outType = outObj.getDbName(); - String inType = inObj.getDbName(); - - if (outObj.isContainer()) { - outType = outObj.getChildDBName(); - } - if (inObj.isContainer()) { - inType = inObj.getChildDBName(); - } - - markParentBoundary(); - Multimap rules = ArrayListMultimap.create(); - EdgeRuleQuery.Builder qB = new EdgeRuleQuery.Builder(outType, inType).edgeType(type); - - try { - if (labels == null) { - rules.putAll(edgeRules.getRules(qB.build())); - } else { - for (String label : labels) { - rules.putAll(edgeRules.getRules(qB.label(label).build())); - } - } - } catch (EdgeRuleNotFoundException e) { - throw new NoEdgeRuleFoundException(e); - } - - final List inLabels = new ArrayList<>(); - final List outLabels = new ArrayList<>(); - - for (EdgeRule rule : rules.values()) { - if (labels != null && !labels.contains(rule.getLabel())) { - return; - } else { - if (Direction.IN.equals(rule.getDirection())) { - inLabels.add(rule.getLabel()); - } else { - outLabels.add(rule.getLabel()); - } - } - } - - if (inLabels.isEmpty() && !outLabels.isEmpty()) { - traversal.outE(outLabels.toArray(new String[outLabels.size()])); - } else if (outLabels.isEmpty() && !inLabels.isEmpty()) { - traversal.inE(inLabels.toArray(new String[inLabels.size()])); - } else { - traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), __.inE(inLabels.toArray(new String[inLabels.size()]))); - } - } - - @Override - public QueryBuilder limit(long amount) { - traversal.limit(amount); - return this; - } - - /** - * @{inheritDoc} - */ - @Override - public E2 getQuery() { - return (E2)this.traversal; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder getParentQuery() { - - return cloneQueryAtStep(parentStepIndex); - } - - @Override - public QueryBuilder getContainerQuery() { - - if (this.parentStepIndex == 0) { - return removeQueryStepsBetween(0, containerStepIndex); - } else { - return cloneQueryAtStep(containerStepIndex); - } - } - - /** - * @{inheritDoc} - */ - @Override - public void markParentBoundary() { - parentStepIndex = stepIndex; - } - - @Override - public void markContainer() { - containerStepIndex = stepIndex; - } - - - /** - * @{inheritDoc} - */ - @Override - public Vertex getStart() { - return this.start; - } - - protected int getParentStepIndex() { - return parentStepIndex; - } - - protected int getContainerStepIndex() { - return containerStepIndex; - } - - protected int getStepIndex() { - return stepIndex; - } - - /** - * end is exclusive - * - * @param start - * @param end - * @return - */ - protected abstract QueryBuilder removeQueryStepsBetween(int start, int end); - - protected void executeQuery() { - - Admin admin; - if (start != null) { - this.completeTraversal = traversal.asAdmin(); - } else { - admin = source.V().asAdmin(); - TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin); - - this.completeTraversal = (Admin) admin; - - } - - } - - @Override - public boolean hasNext() { - if (this.completeTraversal == null) { - executeQuery(); - } - - return this.completeTraversal.hasNext(); - } - - @Override - public E next() { - if (this.completeTraversal == null) { - executeQuery(); - } - - return this.completeTraversal.next(); - } - - @Override - public List toList() { - if (this.completeTraversal == null) { - executeQuery(); - } - return this.completeTraversal.toList(); - } - - protected QueryBuilder has(String key, String value) { - traversal.has(key, value); - - return (QueryBuilder)this; - } }