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 org.apache.tinkerpop.gremlin.process.traversal.Path;
24 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
25 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
26 import org.apache.tinkerpop.gremlin.structure.Edge;
27 import org.apache.tinkerpop.gremlin.structure.Vertex;
28 import org.onap.aai.config.SpringContextAware;
29 import org.onap.aai.db.props.AAIProperties;
30 import org.onap.aai.edges.EdgeIngestor;
31 import org.onap.aai.edges.enums.AAIDirection;
32 import org.onap.aai.edges.enums.EdgeProperty;
33 import org.onap.aai.edges.enums.EdgeType;
34 import org.onap.aai.exceptions.AAIException;
35 import org.onap.aai.introspection.Introspector;
36 import org.onap.aai.introspection.Loader;
37 import org.onap.aai.parsers.query.QueryParser;
38 import org.onap.aai.parsers.query.QueryParserStrategy;
39 import org.springframework.context.ApplicationContext;
41 import javax.ws.rs.core.MultivaluedMap;
42 import java.io.UnsupportedEncodingException;
44 import java.util.Iterator;
45 import java.util.List;
49 * The Class QueryBuilder.
51 public abstract class QueryBuilder<E> implements Iterator<E> {
53 protected final GraphTraversalSource source;
54 protected QueryParserStrategy factory = null;
55 protected Loader loader = null;
56 protected EdgeIngestor edgeRules;
57 protected boolean optimize = false;
58 protected Vertex start = null;
60 protected int parentStepIndex = 0;
61 protected int containerStepIndex = 0;
62 protected int stepIndex = 0;
65 * Instantiates a new query builder.
67 * @param loader the loader
69 public QueryBuilder(Loader loader, GraphTraversalSource source) {
76 * Instantiates a new query builder.
78 * @param loader the loader
79 * @param start the start
81 public QueryBuilder(Loader loader, GraphTraversalSource source, Vertex start) {
88 public void changeLoader(Loader loader) {
92 protected abstract QueryBuilder<E> cloneQueryAtStep(int index);
95 * Gets the vertices by indexed property.
98 * @param value the value
99 * @return the vertices by indexed property
101 public QueryBuilder<Vertex> getVerticesByIndexedProperty(String key, Object value) {
102 return this.getVerticesByProperty(key, value);
106 * Gets the vertices by property.
109 * @param value the value
110 * @return the vertices by property
112 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, List<String> labels) throws AAIException {
418 Introspector out = loader.introspectorFromName(outNodeType);
419 Introspector in = loader.introspectorFromName(inNodeType);
421 QueryBuilder<Vertex> cousinBuilder = null;
422 QueryBuilder<Vertex> treeBuilder = null;
423 QueryBuilder<Vertex> queryBuilder = null;
426 cousinBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.COUSIN, out, in, labels);
427 } catch (AAIException e) {
430 if (cousinBuilder != null) {
432 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
433 } catch (AAIException e) {
435 if (treeBuilder != null) {
436 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder});
438 queryBuilder = this.union(new QueryBuilder[] {cousinBuilder});
441 treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels);
442 queryBuilder = this.union(new QueryBuilder[] {treeBuilder});
448 public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, String outNodeType, String inNodeType)
449 throws AAIException {
450 Introspector out = loader.introspectorFromName(outNodeType);
451 Introspector in = loader.introspectorFromName(inNodeType);
452 return createPrivateEdgeTraversal(type, out, in);
462 * @throws AAIException
464 public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, String outNodeType, String inNodeType,
465 List<String> labels) throws AAIException {
466 Introspector out = loader.introspectorFromName(outNodeType);
467 Introspector in = loader.introspectorFromName(inNodeType);
469 return createEdgeTraversalWithLabels(type, out, in, labels);
480 public abstract QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in,
481 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".
495 * @throws AAIException
497 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType, String inNodeType,
498 Object value) throws AAIException {
499 return this.createEdgeTraversal(type, outNodeType, inNodeType);
503 * This method and it's overloaded counterpart are conditional statements.
504 * This method skips an edge traversal step if there is an optional property missing.
505 * This is necessary in cases such as "if the Optional Property 1 is sent,
506 * find all Nodes of type A with edges to Nodes of type B with property 1,
507 * otherwise, simply find all nodes of type A".
513 * @throws AAIException
515 public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType, String inNodeType,
516 MissingOptionalParameter value) throws AAIException {
517 return (QueryBuilder<Vertex>) this;
526 * @throws AAIException
528 public QueryBuilder<Edge> getEdgesBetween(EdgeType type, String outNodeType, String inNodeType)
529 throws AAIException {
530 this.getEdgesBetweenWithLabels(type, outNodeType, inNodeType, null);
532 return (QueryBuilder<Edge>) this;
543 * @throws AAIException
545 public abstract QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType,
546 List<String> labels) throws AAIException;
549 * Creates the query from URI.
552 * @return the query parser
553 * @throws UnsupportedEncodingException the unsupported encoding exception
554 * @throws AAIException the AAI exception
556 public abstract QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException;
559 * Creates the query from URI.
562 * @param queryParams the query params
563 * @return the query parser
564 * @throws UnsupportedEncodingException the unsupported encoding exception
565 * @throws AAIException the AAI exception
567 public abstract QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams)
568 throws UnsupportedEncodingException, AAIException;
571 * Creates a queryparser from a given object name.
573 * @param objName - name of the object type as it appears in the database
576 public abstract QueryParser createQueryFromObjectName(String objName);
579 * Creates the query from relationship.
581 * @param relationship the relationship
582 * @return the query parser
583 * @throws UnsupportedEncodingException the unsupported encoding exception
584 * @throws AAIException the AAI exception
586 public abstract QueryParser createQueryFromRelationship(Introspector relationship)
587 throws UnsupportedEncodingException, AAIException;
590 * Gets the parent query.
592 * @return the parent query
594 public abstract QueryBuilder<E> getParentQuery();
601 public abstract <E2> E2 getQuery();
606 public abstract void markParentBoundary();
608 public abstract QueryBuilder<E> limit(long amount);
613 * @param start the start
614 * @return the query builder
616 public abstract QueryBuilder<E> newInstance(Vertex start);
621 * @return the query builder
623 public abstract QueryBuilder<E> newInstance();
630 public abstract Vertex getStart();
632 protected Object correctObjectType(Object obj) {
634 if (obj != null && obj.getClass().equals(Long.class)) {
635 return new Integer(obj.toString());
642 * uses all fields in the introspector to create a query
647 public abstract QueryBuilder<Vertex> exactMatchQuery(Introspector obj);
650 * lets you join any number of QueryBuilders
651 * <b>be careful about starting with a union it will not use indexes</b>
656 public abstract QueryBuilder<E> union(QueryBuilder<E>... builder);
658 public abstract QueryBuilder<E> where(QueryBuilder<E>... builder);
660 public abstract QueryBuilder<E> or(QueryBuilder<E>... builder);
662 public abstract QueryBuilder<E> store(String name);
664 public abstract QueryBuilder<E> cap(String name);
666 public abstract QueryBuilder<E> unfold();
668 public abstract QueryBuilder<E> fold();
670 public abstract QueryBuilder<E> id();
672 public abstract QueryBuilder<E> dedup();
674 public abstract QueryBuilder<E> emit();
676 public abstract QueryBuilder<E> repeat(QueryBuilder<E> builder);
678 public abstract QueryBuilder<Edge> outE();
680 public abstract QueryBuilder<Edge> inE();
682 public abstract QueryBuilder<Vertex> inV();
684 public abstract QueryBuilder<Vertex> outV();
686 public abstract QueryBuilder<E> not(QueryBuilder<E> builder);
688 public abstract QueryBuilder<E> as(String name);
690 public abstract QueryBuilder<E> select(String name);
692 public abstract QueryBuilder<E> select(String... names);
694 public abstract QueryBuilder<E> until(QueryBuilder<E> builder);
696 public abstract QueryBuilder<E> groupCount();
698 public abstract QueryBuilder<E> by(String name);
700 public abstract QueryBuilder<E> valueMap();
702 public abstract QueryBuilder<E> valueMap(String... names);
704 public abstract QueryBuilder<E> both();
706 public abstract QueryBuilder<Tree> tree();
709 * Used to prevent the traversal from repeating its path through the graph.
710 * See http://tinkerpop.apache.org/docs/3.0.1-incubating/#simplepath-step for more info.
712 * @return a QueryBuilder with the simplePath step appended to its traversal
714 public abstract QueryBuilder<E> simplePath();
718 * @return QueryBuilder with the path step appended to its traversal
720 public abstract QueryBuilder<Path> path();
722 public abstract void markContainer();
724 public abstract QueryBuilder<E> getContainerQuery();
726 public abstract List<E> toList();
729 * Used to skip step if there is an optional property missing.
735 public QueryBuilder<Vertex> getVerticesByProperty(String key, MissingOptionalParameter value) {
736 return (QueryBuilder<Vertex>) this;
740 * TODO the edge direction is hardcoded here, make it more generic
741 * Returns the parent edge of the vertex
745 public QueryBuilder<Edge> getParentEdge() {
746 this.outE().has(EdgeProperty.CONTAINS.toString(), AAIDirection.IN.toString());
747 return (QueryBuilder<Edge>) this;
751 * TODO the edge direction is hardcoded here, make it more generic
752 * Returns the parent vertex of the vertex
756 public QueryBuilder<Vertex> getParentVertex() {
757 this.getParentEdge().inV();
758 return (QueryBuilder<Vertex>) this;
761 protected abstract QueryBuilder<Edge> has(String key, String value);
763 protected void initEdgeIngestor() {
764 // TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
765 ApplicationContext ctx = SpringContextAware.getApplicationContext();
766 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
770 protected void setEdgeIngestor(EdgeIngestor ei) {
774 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) {
775 return getVerticesByProperty(key, value);
778 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key) {
779 return getVerticesByProperty(key);
782 public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, MissingOptionalParameter value) {
783 return getVerticesByProperty(key, value);
786 protected abstract void vertexHas(String key, Object value) ;
788 protected abstract void vertexHasNot(String key);
790 protected abstract void vertexHas(String key);
792 //TODO: This probably is not required but need to test
793 // protected abstract void vertexHas(final String key, final P<?> predicate);