2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.aai.query.builder;
23 import java.io.UnsupportedEncodingException;
25 import java.util.Iterator;
26 import java.util.List;
29 import javax.ws.rs.core.MultivaluedMap;
31 import org.apache.tinkerpop.gremlin.process.traversal.Path;
32 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
33 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
34 import org.apache.tinkerpop.gremlin.structure.Edge;
35 import org.apache.tinkerpop.gremlin.structure.Vertex;
36 import org.onap.aai.config.SpringContextAware;
37 import org.onap.aai.db.props.AAIProperties;
38 import org.onap.aai.edges.EdgeIngestor;
39 import org.onap.aai.edges.enums.AAIDirection;
40 import org.onap.aai.edges.enums.EdgeProperty;
41 import org.onap.aai.edges.enums.EdgeType;
42 import org.onap.aai.exceptions.AAIException;
43 import org.onap.aai.introspection.Introspector;
44 import org.onap.aai.introspection.Loader;
45 import org.onap.aai.parsers.query.QueryParser;
46 import org.onap.aai.parsers.query.QueryParserStrategy;
47 import org.springframework.context.ApplicationContext;
50 * The Class QueryBuilder.
52 public abstract class QueryBuilder<E> implements Iterator<E> {
54 protected final GraphTraversalSource source;
55 protected QueryParserStrategy factory = null;
56 protected Loader loader = null;
57 protected EdgeIngestor edgeRules;
58 protected boolean optimize = false;
59 protected Vertex start = null;
61 protected int parentStepIndex = 0;
62 protected int containerStepIndex = 0;
63 protected int stepIndex = 0;
66 * Instantiates a new query builder.
68 * @param loader the loader
70 public QueryBuilder(Loader loader, GraphTraversalSource source) {
77 * Instantiates a new query builder.
79 * @param loader the loader
80 * @param start the start
82 public QueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
89 public void changeLoader(Loader loader) {
93 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
96 * Gets the vertices by indexed property.
99 * @param value the value
100 * @return the vertices by indexed property
102 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
103 return this.getVerticesByProperty(key, value);
107 * Gets the vertices by property.
110 * @param value the value
111 * @return the vertices by property
113 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, Object value);
116 * Gets the edges by property.
119 * @param value the value
120 * @return the vertices by property
122 public QueryBuilder<Edge> getEdgesByProperty(String key, Object value) {
123 return this.has(key, value.toString());
127 * filters by all the values for this property
131 * @return vertices that match these values
133 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, List<?> values) {
134 return this.getVerticesByProperty(key, values);
138 * filters by all the values for this property
142 * @return vertices that match these values
144 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values);
147 * filters by all the values for this property
150 * @param value in comma delimited string format
151 * @return vertices that match these values
153 public abstract QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value);
156 * Gets the vertices that have this property key.
159 * @return the vertices by property
161 public abstract QueryBuilder<Vertex> getVerticesByProperty(String key);
164 * Gets the vertices that do not have this property key.
167 * @return the vertices by property
169 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key);
172 * filters by elements that start with the value for this property
176 * @return vertices that match these values
178 public abstract QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value);
181 * Gets the vertices that are excluded by property.
184 * @param value the value
185 * @return the vertices by property
187 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value);
190 * filters by all the values for this property and excludes the vertices
194 * @return vertices that match these values
196 public QueryBuilder<Vertex> getVerticesExcludeByIndexedProperty(String key, List<?> values) {
197 return this.getVerticesExcludeByProperty(key, values);
201 * filters by all the values for this property and excludes the vertices
205 * @return vertices that match these values
207 public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, List<?> values);
210 * filters by all the values greater than for this property
214 * @return vertices that match these values
216 public abstract QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value);
219 * filters by all the values less than for this property
223 * @return vertices that match these values
226 public abstract QueryBuilder<Vertex> getVerticesLessThanProperty(String key, Object value);
229 * Gets the child vertices from parent.
231 * @param parentKey the parent key
232 * @param parentValue the parent value
233 * @param childType the child type
234 * @return the child vertices from parent
236 public abstract QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue,
240 * Gets the typed vertices by map.
242 * @param type the type
244 * @return the typed vertices by map
246 public abstract QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map);
249 * Creates the DB query.
252 * @return the query builder
254 public QueryBuilder<Vertex> createDBQuery(Introspector obj) {
255 this.createKeyQuery(obj);
256 this.createContainerQuery(obj);
257 return (QueryBuilder<Vertex>) this;
261 * Creates the key query.
264 * @return the query builder
266 public abstract QueryBuilder<Vertex> createKeyQuery(Introspector obj);
269 * Creates the container query.
272 * @return the query builder
274 public abstract QueryBuilder<Vertex> createContainerQuery(Introspector obj);
277 * Creates the edge traversal.
279 * @param parent the parent
280 * @param child the child
281 * @return the query builder
283 public abstract QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child)
286 public abstract QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, Object value);
288 public QueryBuilder<Vertex> getVerticesByBooleanProperty(String key, MissingOptionalParameter value) {
289 return (QueryBuilder<Vertex>) this;
293 * Creates the private edge traversal.
295 * @param parent the parent
296 * @param child the child
297 * @return the query builder
299 public abstract QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent,
300 Introspector child) throws AAIException;
303 * Creates the edge traversal.
305 * @param parent the parent
306 * @param child the child
307 * @return the query builder
309 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Vertex parent, Introspector child)
310 throws AAIException {
311 String nodeType = parent.<String>property(AAIProperties.NODE_TYPE).orElse(null);
312 this.createEdgeTraversal(type, nodeType, child.getDbName());
313 return (QueryBuilder<Vertex>) this;
322 * @throws AAIException
324 public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, String outNodeType, String inNodeType)
325 throws AAIException {
326 Introspector out = loader.introspectorFromName(outNodeType);
327 Introspector in = loader.introspectorFromName(inNodeType);
329 return createEdgeTraversal(type, out, in);
338 * @throws AAIException
340 public QueryBuilder<Vertex> createEdgeTraversal(String edgeType, String outNodeType, String inNodeType)
341 throws AAIException {
343 * When the optional parameter edgetype is sent it is a string that needs to be converted to Enum
345 EdgeType type = EdgeType.valueOf(edgeType);
346 Introspector out = loader.introspectorFromName(outNodeType);
347 Introspector in = loader.introspectorFromName(inNodeType);
349 return createEdgeTraversal(type, out, in);
358 * @throws AAIException
360 public QueryBuilder<Vertex> createEdgeTraversal(MissingOptionalParameter edgeType, String outNodeType,
361 String inNodeType) throws AAIException {
363 * When no optional parameter edgetype is sent get all edges between the 2 nodetypes
365 return this.createEdgeTraversal(outNodeType, inNodeType);
374 * @throws AAIException
376 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(MissingOptionalParameter edgeType, String outNodeType,
377 String inNodeType, List<String> labels) throws AAIException {
379 * When no optional parameter edgetype is sent get all edges between the 2 nodetypes
381 return this.createEdgeTraversalWithLabels(outNodeType, inNodeType, labels);
384 public QueryBuilder<Vertex> createEdgeTraversal(String outNodeType, String inNodeType) throws AAIException {
386 Introspector out = loader.introspectorFromName(outNodeType);
387 Introspector in = loader.introspectorFromName(inNodeType);
389 QueryBuilder<Vertex> cousinBuilder = null;
390 QueryBuilder<Vertex> treeBuilder = null;
391 QueryBuilder<Vertex> queryBuilder = null;
394 cousinBuilder = this.newInstance().createEdgeTraversal(EdgeType.COUSIN, out, in);
395 } catch (AAIException e) {
398 if (cousinBuilder != null) {
400 treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
401 } catch (AAIException e) {
403 if (treeBuilder != null) {
404 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder});
406 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder});
409 treeBuilder = this.newInstance().createEdgeTraversal(EdgeType.TREE, out, in);
410 queryBuilder = this.union(new QueryBuilder[] {treeBuilder});
416 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(String outNodeType, String inNodeType,
417 List<String> labels) throws AAIException {
419 Introspector out = loader.introspectorFromName(outNodeType);
420 Introspector in = loader.introspectorFromName(inNodeType);
422 QueryBuilder<Vertex> cousinBuilder = null;
423 QueryBuilder<Vertex> treeBuilder = null;
424 QueryBuilder<Vertex> queryBuilder = null;
427 cousinBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.COUSIN, out, in, labels);
428 } catch (AAIException e) {
431 if (cousinBuilder != null) {
433 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
434 } catch (AAIException e) {
436 if (treeBuilder != null) {
437 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder});
439 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder});
442 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
443 queryBuilder = this.union(new QueryBuilder[] {treeBuilder});
449 public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, String outNodeType, String inNodeType)
450 throws AAIException {
451 Introspector out = loader.introspectorFromName(outNodeType);
452 Introspector in = loader.introspectorFromName(inNodeType);
453 return createPrivateEdgeTraversal(type, out, in);
463 * @throws AAIException
465 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, String outNodeType, String inNodeType,
466 List<String> labels) throws AAIException {
467 Introspector out = loader.introspectorFromName(outNodeType);
468 Introspector in = loader.introspectorFromName(inNodeType);
470 return createEdgeTraversalWithLabels(type, out, in, labels);
481 public abstract QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in,
482 List<String> labels) throws AAIException;
485 * This method and it's overloaded counterpart are conditional statements.
486 * This method creates an edge traversal step if an optional property is present
487 * This is necessary in cases such as "if the Optional Property 1 is sent,
488 * find all Nodes of type A with edges to Nodes of type B with property 1,
489 * otherwise, simply find all nodes of type A".
496 * @throws AAIException
498 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType,
499 String inNodeType, Object value) throws AAIException {
500 return this.createEdgeTraversal(type, outNodeType, inNodeType);
504 * This method and it's overloaded counterpart are conditional statements.
505 * This method skips an edge traversal step if there is an optional property missing.
506 * This is necessary in cases such as "if the Optional Property 1 is sent,
507 * find all Nodes of type A with edges to Nodes of type B with property 1,
508 * otherwise, simply find all nodes of type A".
515 * @throws AAIException
517 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType,
518 String inNodeType, MissingOptionalParameter value) throws AAIException {
519 return (QueryBuilder<Vertex>) this;
528 * @throws AAIException
530 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType)
531 throws AAIException {
532 this.getEdgesBetweenWithLabels(type, outNodeType, inNodeType, null);
534 return (QueryBuilder<Edge>) this;
545 * @throws AAIException
547 public abstract QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType,
548 List<String> labels) throws AAIException;
551 * Creates the query from URI.
554 * @return the query parser
555 * @throws UnsupportedEncodingException the unsupported encoding exception
556 * @throws AAIException the AAI exception
558 public abstract QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException;
561 * Creates the query from URI.
564 * @param queryParams the query params
565 * @return the query parser
566 * @throws UnsupportedEncodingException the unsupported encoding exception
567 * @throws AAIException the AAI exception
569 public abstract QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
570 throws UnsupportedEncodingException, AAIException;
573 * Creates a queryparser from a given object name.
575 * @param objName - name of the object type as it appears in the database
578 public abstract QueryParser createQueryFromObjectName(String objName);
581 * Creates the query from relationship.
583 * @param relationship the relationship
584 * @return the query parser
585 * @throws UnsupportedEncodingException the unsupported encoding exception
586 * @throws AAIException the AAI exception
588 public abstract QueryParser createQueryFromRelationship(Introspector relationship)
589 throws UnsupportedEncodingException, AAIException;
592 * Gets the parent query.
594 * @return the parent query
596 public abstract QueryBuilder<E> getParentQuery();
603 public abstract <E2> E2 getQuery();
608 public abstract void markParentBoundary();
610 public abstract QueryBuilder<E> limit(long amount);
615 * @param start the start
616 * @return the query builder
618 public abstract QueryBuilder<E> newInstance(Vertex start);
623 * @return the query builder
625 public abstract QueryBuilder<E> newInstance();
632 public abstract Vertex getStart();
634 protected Object correctObjectType(Object obj) {
636 if (obj != null && obj.getClass().equals(Long.class)) {
637 return Integer.valueOf(obj.toString());
644 * uses all fields in the introspector to create a query
649 public abstract QueryBuilder<Vertex> exactMatchQuery(Introspector obj);
652 * lets you join any number of QueryBuilders
653 * <b>be careful about starting with a union it will not use indexes</b>
658 public abstract QueryBuilder<E> union(QueryBuilder<E>... builder);
660 public abstract QueryBuilder<E> where(QueryBuilder<E>... builder);
662 public abstract QueryBuilder<E> or(QueryBuilder<E>... builder);
664 public abstract QueryBuilder<E> store(String name);
666 public abstract QueryBuilder<E> cap(String name);
668 public abstract QueryBuilder<E> unfold();
670 public abstract QueryBuilder<E> fold();
672 public abstract QueryBuilder<E> id();
674 public abstract QueryBuilder<E> dedup();
676 public abstract QueryBuilder<E> emit();
678 public abstract QueryBuilder<E> repeat(QueryBuilder<E> builder);
680 public abstract QueryBuilder<Edge> outE();
682 public abstract QueryBuilder<Edge> inE();
684 public abstract QueryBuilder<Vertex> inV();
686 public abstract QueryBuilder<Vertex> outV();
688 public abstract QueryBuilder<E> not(QueryBuilder<E> builder);
690 public abstract QueryBuilder<E> as(String name);
692 public abstract QueryBuilder<E> select(String name);
694 public abstract QueryBuilder<E> select(String... names);
696 public abstract QueryBuilder<E> until(QueryBuilder<E> builder);
698 public abstract QueryBuilder<E> groupCount();
700 public abstract QueryBuilder<E> by(String name);
702 public abstract QueryBuilder<E> valueMap();
704 public abstract QueryBuilder<E> valueMap(String... names);
706 public abstract QueryBuilder<E> both();
708 public abstract QueryBuilder<Tree> tree();
711 * Used to prevent the traversal from repeating its path through the graph.
712 * See http://tinkerpop.apache.org/docs/3.0.1-incubating/#simplepath-step for more info.
714 * @return a QueryBuilder with the simplePath step appended to its traversal
716 public abstract QueryBuilder<E> simplePath();
720 * @return QueryBuilder with the path step appended to its traversal
722 public abstract QueryBuilder<Path> path();
724 public abstract void markContainer();
726 public abstract QueryBuilder<E> getContainerQuery();
728 public abstract List<E> toList();
731 * Used to skip step if there is an optional property missing.
737 public QueryBuilder<Vertex> getVerticesByProperty(String key, MissingOptionalParameter value) {
738 return (QueryBuilder<Vertex>) this;
742 * TODO the edge direction is hardcoded here, make it more generic
743 * Returns the parent edge of the vertex
747 public QueryBuilder<Edge> getParentEdge() {
748 this.outE().has(EdgeProperty.CONTAINS.toString(), AAIDirection.IN.toString());
749 return (QueryBuilder<Edge>) this;
753 * TODO the edge direction is hardcoded here, make it more generic
754 * Returns the parent vertex of the vertex
758 public QueryBuilder<Vertex> getParentVertex() {
759 this.getParentEdge().inV();
760 return (QueryBuilder<Vertex>) this;
763 protected abstract QueryBuilder<Edge> has(String key, String value);
765 protected void initEdgeIngestor() {
766 // TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
767 ApplicationContext ctx = SpringContextAware.getApplicationContext();
768 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
772 protected void setEdgeIngestor(EdgeIngestor ei) {
776 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) {
777 return getVerticesByProperty(key, value);
780 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key) {
781 return getVerticesByProperty(key);
784 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, MissingOptionalParameter value) {
785 return getVerticesByProperty(key, value);
788 protected abstract void vertexHas(String key, Object value);
790 protected abstract void vertexHasNot(String key);
792 protected abstract void vertexHas(String key);
794 // TODO: This probably is not required but need to test
795 // protected abstract void vertexHas(final String key, final P<?> predicate);