diff options
author | Fiete Ostkamp <Fiete.Ostkamp@telekom.de> | 2024-07-03 13:47:19 +0200 |
---|---|---|
committer | Fiete Ostkamp <Fiete.Ostkamp@telekom.de> | 2024-07-03 13:51:50 +0200 |
commit | 912bfd1019b001e1897c33887cc84dd86c56fce6 (patch) | |
tree | a1f0c8c6719de1b595c0d6980bda8680d567473e | |
parent | 469bb923ddcadab821a3541afca6f6a73a7f6ad1 (diff) |
Pagination will throw an IllegalArgumentException if there are no vertices of the requested type
- provide empty PaginationResponse when traversal.next() throws IllegalArgumentException
Issue-ID: AAI-3917
Change-Id: I280f216050ea16953015023146d40674e067f028
Signed-off-by: Fiete Ostkamp <Fiete.Ostkamp@telekom.de>
-rw-r--r-- | aai-aaf-auth/pom.xml | 2 | ||||
-rw-r--r-- | aai-annotations/pom.xml | 2 | ||||
-rw-r--r-- | aai-auth/pom.xml | 2 | ||||
-rw-r--r-- | aai-common-docker/aai-common-images/pom.xml | 4 | ||||
-rw-r--r-- | aai-common-docker/aai-haproxy-image/pom.xml | 4 | ||||
-rw-r--r-- | aai-common-docker/pom.xml | 2 | ||||
-rw-r--r-- | aai-core/pom.xml | 2 | ||||
-rw-r--r-- | aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java | 2075 | ||||
-rw-r--r-- | aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java | 2017 | ||||
-rw-r--r-- | aai-els-onap-logging/pom.xml | 2 | ||||
-rw-r--r-- | aai-failover/pom.xml | 2 | ||||
-rw-r--r-- | aai-parent/pom.xml | 2 | ||||
-rw-r--r-- | aai-rest/pom.xml | 2 | ||||
-rw-r--r-- | aai-schema-abstraction/pom.xml | 2 | ||||
-rw-r--r-- | aai-schema-ingest/pom.xml | 2 | ||||
-rw-r--r-- | aai-utils/pom.xml | 2 | ||||
-rw-r--r-- | pom.xml | 2 | ||||
-rw-r--r-- | version.properties | 2 |
18 files changed, 2077 insertions, 2051 deletions
diff --git a/aai-aaf-auth/pom.xml b/aai-aaf-auth/pom.xml index 87bb6033..f0a95f51 100644 --- a/aai-aaf-auth/pom.xml +++ b/aai-aaf-auth/pom.xml @@ -6,7 +6,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-aaf-auth</artifactId> diff --git a/aai-annotations/pom.xml b/aai-annotations/pom.xml index 6580416b..cdc8e975 100644 --- a/aai-annotations/pom.xml +++ b/aai-annotations/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-annotations</artifactId> diff --git a/aai-auth/pom.xml b/aai-auth/pom.xml index 19ac818a..85683d8c 100644 --- a/aai-auth/pom.xml +++ b/aai-auth/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-auth</artifactId> diff --git a/aai-common-docker/aai-common-images/pom.xml b/aai-common-docker/aai-common-images/pom.xml index 12d0077b..ed0a9c8f 100644 --- a/aai-common-docker/aai-common-images/pom.xml +++ b/aai-common-docker/aai-common-images/pom.xml @@ -25,11 +25,11 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-common-docker</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> </parent> <artifactId>aai-common-images</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <packaging>pom</packaging> <name>aai-aai-common-images</name> <description>Contains dockerfiles for aai-common images (alpine and ubuntu based).</description> diff --git a/aai-common-docker/aai-haproxy-image/pom.xml b/aai-common-docker/aai-haproxy-image/pom.xml index b0019819..259c0fe1 100644 --- a/aai-common-docker/aai-haproxy-image/pom.xml +++ b/aai-common-docker/aai-haproxy-image/pom.xml @@ -25,11 +25,11 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-common-docker</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> </parent> <artifactId>aai-haproxy-image</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <packaging>pom</packaging> <name>aai-aai-haproxy-image</name> <description>Contains dockerfiles for aai-haproxy image.</description> diff --git a/aai-common-docker/pom.xml b/aai-common-docker/pom.xml index 4a637bbf..0a28f3e5 100644 --- a/aai-common-docker/pom.xml +++ b/aai-common-docker/pom.xml @@ -26,7 +26,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> diff --git a/aai-core/pom.xml b/aai-core/pom.xml index cd78bff2..aedc7b40 100644 --- a/aai-core/pom.xml +++ b/aai-core/pom.xml @@ -26,7 +26,7 @@ limitations under the License. <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-core</artifactId> 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 8d7da688..198712b7 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 @@ -20,1000 +20,1002 @@ * ============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.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslator; -import org.apache.tinkerpop.gremlin.process.traversal.Order; -import org.apache.tinkerpop.gremlin.process.traversal.P; -import org.apache.tinkerpop.gremlin.process.traversal.Path; -import org.apache.tinkerpop.gremlin.process.traversal.Pop; -import org.apache.tinkerpop.gremlin.process.traversal.Scope; -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; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; -import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; -import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; -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.query.entities.PaginationResult; -import org.onap.aai.schema.enums.ObjectMetadata; -import org.onap.aai.schema.enums.PropertyMetadata; -import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + 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.Collections; + import java.util.List; + import java.util.Map; + import java.util.Optional; + import java.util.Set; + + import org.apache.tinkerpop.gremlin.groovy.jsr223.GroovyTranslator; + import org.apache.tinkerpop.gremlin.process.traversal.Order; + import org.apache.tinkerpop.gremlin.process.traversal.P; + import org.apache.tinkerpop.gremlin.process.traversal.Path; + import org.apache.tinkerpop.gremlin.process.traversal.Pop; + import org.apache.tinkerpop.gremlin.process.traversal.Scope; + 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; + import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; + import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; + import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; + import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; + 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.query.entities.PaginationResult; + import org.onap.aai.schema.enums.ObjectMetadata; + import org.onap.aai.schema.enums.PropertyMetadata; + import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException; + import org.slf4j.Logger; + import org.slf4j.LoggerFactory; + + /** + * The Class GraphTraversalBuilder. + */ + public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { + + private static final Logger LOGGER = LoggerFactory.getLogger(GraphTraversalBuilder.class); + + private final GroovyTranslator groovyTranslator = GroovyTranslator.of("source"); + + protected GraphTraversal<Vertex, E> traversal = null; + protected Admin<Vertex, E> completeTraversal = null; + + protected QueryBuilder<E> containerQuery; + protected QueryBuilder<E> parentQuery; + + /** + * Instantiates a new graph traversal builder. + * + * @param loader the loader + */ + public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) { + super(loader, source); + traversal = (GraphTraversal<Vertex, E>) __.<E>start(); + + } + + public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, GraphTraversal<Vertex, E> traversal) { + super(loader, source); + this.traversal = traversal; + + } + + /** + * 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); + + traversal = (GraphTraversal<Vertex, E>) __.__(start); + + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) { + + // correct value call because the index is registered as an Integer + this.vertexHas(key, this.correctObjectType(value)); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + @Override + protected void vertexHas(String key, Object value) { + traversal.has(key, value); + } + + @Override + protected void vertexHasNot(String key) { + traversal.hasNot(key); + } + + @Override + protected void vertexHas(String key) { + traversal.has(key); + } + + // 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); + * } + */ + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) { + + // this is because the index is registered as an Integer + List<Object> correctedValues = new ArrayList<>(); + for (Object item : values) { + correctedValues.add(this.correctObjectType(item)); + } + + this.vertexHas(key, P.within(correctedValues)); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + public QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value) { + ArrayList<String> 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<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> 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)); + + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getVerticesByProperty(String key) { + this.vertexHas(key); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) { + this.vertexHasNot(key); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> 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<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getVerticesExcludeByProperty(final String key, final List<?> values) { + + // this is because the index is registered as an Integer + List<Object> correctedValues = new ArrayList<>(); + for (Object item : values) { + correctedValues.add(this.correctObjectType(item)); + } + + this.vertexHas(key, P.without(correctedValues)); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + @Override + public QueryBuilder<Vertex> getVerticesGreaterThanProperty(final String key, Object value) { + this.vertexHas(key, P.gte(this.correctObjectType(value))); + + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + @Override + public QueryBuilder<Vertex> getVerticesLessThanProperty(final String key, Object value) { + this.vertexHas(key, P.lte(this.correctObjectType(value))); + + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) { + traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) { + + for (Map.Entry<String, String> es : map.entrySet()) { + this.vertexHas(es.getKey(), es.getValue()); + stepIndex++; + } + traversal.has(AAIProperties.NODE_TYPE, type); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + @Override + public QueryBuilder<Vertex> 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<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> createKeyQuery(Introspector obj) { + Set<String> keys = obj.getKeys(); + Object val; + for (String key : keys) { + val = obj.getValue(key); + Optional<String> 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<Vertex>) this; + } + + @Override + public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) { + this.createKeyQuery(obj); + allPropertiesQuery(obj); + this.createContainerQuery(obj); + return (QueryBuilder<Vertex>) this; + } + + private void allPropertiesQuery(Introspector obj) { + Set<String> props = obj.getProperties(); + Set<String> keys = obj.getKeys(); + Object val; + for (String prop : props) { + if (obj.isSimpleType(prop) && !keys.contains(prop)) { + val = obj.getValue(prop); + if (val != null) { + Optional<String> 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<Vertex> 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<Vertex>) this; + } + + /** + * @throws NoEdgeRuleFoundException + * @throws AAIException + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) + throws AAIException { + createTraversal(type, parent, child, false); + return (QueryBuilder<Vertex>) this; + + } + + @Override + public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) + throws AAIException { + this.createTraversal(type, parent, child, true); + return (QueryBuilder<Vertex>) 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<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, + List<String> labels) throws AAIException { + this.edgeQueryToVertex(type, out, in, labels); + return (QueryBuilder<Vertex>) this; + } + + private Traversal<Vertex, Vertex>[] 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<Traversal<Vertex, Vertex>> 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<String, EdgeRule> rules = ArrayListMultimap.create(); + try { + rules = edgeRules.getRules(qB.edgeType(type).build()); + } catch (EdgeRuleNotFoundException e) { + throw new NoEdgeRuleFoundException(e); + } + + GraphTraversal<Vertex, Vertex> innerTraversal = __.start(); + + final List<String> inLabels = new ArrayList<>(); + final List<String> 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<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, + List<String> labels) throws AAIException { + Introspector outObj = loader.introspectorFromName(outNodeType); + Introspector inObj = loader.introspectorFromName(inNodeType); + this.edgeQuery(type, outObj, inObj, labels); + + return (QueryBuilder<Edge>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<E> union(QueryBuilder... builder) { + GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length]; + for (int i = 0; i < builder.length; i++) { + traversals[i] = (GraphTraversal<Vertex, Vertex>) builder[i].getQuery(); + } + this.traversal.union(traversals); + stepIndex++; + + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<E> where(QueryBuilder... builder) { + for (int i = 0; i < builder.length; i++) { + this.traversal.where((GraphTraversal<Vertex, Vertex>) builder[i].getQuery()); + stepIndex++; + } + + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<E> or(QueryBuilder... builder) { + GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length]; + for (int i = 0; i < builder.length; i++) { + traversals[i] = (GraphTraversal<Vertex, Vertex>) builder[i].getQuery(); + } + this.traversal.or(traversals); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> store(String name) { + + this.traversal.store(name); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> cap(String name) { + this.traversal.cap(name); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> unfold() { + this.traversal.unfold(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> dedup() { + + this.traversal.dedup(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> emit() { + + this.traversal.emit(); + stepIndex++; + + return this; + + } + + @Override + public QueryBuilder<E> repeat(QueryBuilder<E> builder) { + + this.traversal.repeat((GraphTraversal<Vertex, E>) builder.getQuery()); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> until(QueryBuilder<E> builder) { + this.traversal.until((GraphTraversal<Vertex, E>) builder.getQuery()); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> groupCount() { + this.traversal.groupCount(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> both() { + this.traversal.both(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<Tree> tree() { + + this.traversal.tree(); + stepIndex++; + + return (QueryBuilder<Tree>) this; + } + + @Override + public QueryBuilder<E> by(String name) { + this.traversal.by(name); + stepIndex++; + + return this; + } -/** - * The Class GraphTraversalBuilder. - */ -public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { - - private static final Logger LOGGER = LoggerFactory.getLogger(GraphTraversalBuilder.class); - - private final GroovyTranslator groovyTranslator = GroovyTranslator.of("source"); - - protected GraphTraversal<Vertex, E> traversal = null; - protected Admin<Vertex, E> completeTraversal = null; - - protected QueryBuilder<E> containerQuery; - protected QueryBuilder<E> parentQuery; - - /** - * Instantiates a new graph traversal builder. - * - * @param loader the loader - */ - public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) { - super(loader, source); - traversal = (GraphTraversal<Vertex, E>) __.<E>start(); - - } - - public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, GraphTraversal<Vertex, E> traversal) { - super(loader, source); - this.traversal = traversal; - - } - - /** - * 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); - - traversal = (GraphTraversal<Vertex, E>) __.__(start); - - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) { - - // correct value call because the index is registered as an Integer - this.vertexHas(key, this.correctObjectType(value)); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - @Override - protected void vertexHas(String key, Object value) { - traversal.has(key, value); - } - - @Override - protected void vertexHasNot(String key) { - traversal.hasNot(key); - } - - @Override - protected void vertexHas(String key) { - traversal.has(key); - } - - // 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); - * } - */ - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> getVerticesByProperty(final String key, final List<?> values) { - - // this is because the index is registered as an Integer - List<Object> correctedValues = new ArrayList<>(); - for (Object item : values) { - correctedValues.add(this.correctObjectType(item)); - } - - this.vertexHas(key, P.within(correctedValues)); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - public QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value) { - ArrayList<String> 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<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> 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)); - - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> getVerticesByProperty(String key) { - this.vertexHas(key); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) { - this.vertexHasNot(key); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> 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<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> getVerticesExcludeByProperty(final String key, final List<?> values) { - - // this is because the index is registered as an Integer - List<Object> correctedValues = new ArrayList<>(); - for (Object item : values) { - correctedValues.add(this.correctObjectType(item)); - } - - this.vertexHas(key, P.without(correctedValues)); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - @Override - public QueryBuilder<Vertex> getVerticesGreaterThanProperty(final String key, Object value) { - this.vertexHas(key, P.gte(this.correctObjectType(value))); - - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - @Override - public QueryBuilder<Vertex> getVerticesLessThanProperty(final String key, Object value) { - this.vertexHas(key, P.lte(this.correctObjectType(value))); - - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> getChildVerticesFromParent(String parentKey, String parentValue, String childType) { - traversal.has(parentKey, parentValue).has(AAIProperties.NODE_TYPE, childType); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) { - - for (Map.Entry<String, String> es : map.entrySet()) { - this.vertexHas(es.getKey(), es.getValue()); - stepIndex++; - } - traversal.has(AAIProperties.NODE_TYPE, type); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - @Override - public QueryBuilder<Vertex> 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<Vertex>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> createKeyQuery(Introspector obj) { - Set<String> keys = obj.getKeys(); - Object val; - for (String key : keys) { - val = obj.getValue(key); - Optional<String> 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<Vertex>) this; - } - - @Override - public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) { - this.createKeyQuery(obj); - allPropertiesQuery(obj); - this.createContainerQuery(obj); - return (QueryBuilder<Vertex>) this; - } - - private void allPropertiesQuery(Introspector obj) { - Set<String> props = obj.getProperties(); - Set<String> keys = obj.getKeys(); - Object val; - for (String prop : props) { - if (obj.isSimpleType(prop) && !keys.contains(prop)) { - val = obj.getValue(prop); - if (val != null) { - Optional<String> 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<Vertex> 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<Vertex>) this; - } - - /** - * @throws NoEdgeRuleFoundException - * @throws AAIException - * @{inheritDoc} - */ - @Override - public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) - throws AAIException { - createTraversal(type, parent, child, false); - return (QueryBuilder<Vertex>) this; - - } - - @Override - public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) - throws AAIException { - this.createTraversal(type, parent, child, true); - return (QueryBuilder<Vertex>) 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<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, - List<String> labels) throws AAIException { - this.edgeQueryToVertex(type, out, in, labels); - return (QueryBuilder<Vertex>) this; - } - - private Traversal<Vertex, Vertex>[] 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<Traversal<Vertex, Vertex>> 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<String, EdgeRule> rules = ArrayListMultimap.create(); - try { - rules = edgeRules.getRules(qB.edgeType(type).build()); - } catch (EdgeRuleNotFoundException e) { - throw new NoEdgeRuleFoundException(e); - } - - GraphTraversal<Vertex, Vertex> innerTraversal = __.start(); - - final List<String> inLabels = new ArrayList<>(); - final List<String> 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<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, - List<String> labels) throws AAIException { - Introspector outObj = loader.introspectorFromName(outNodeType); - Introspector inObj = loader.introspectorFromName(inNodeType); - this.edgeQuery(type, outObj, inObj, labels); - - return (QueryBuilder<Edge>) this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<E> union(QueryBuilder... builder) { - GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length]; - for (int i = 0; i < builder.length; i++) { - traversals[i] = (GraphTraversal<Vertex, Vertex>) builder[i].getQuery(); - } - this.traversal.union(traversals); - stepIndex++; - - return this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<E> where(QueryBuilder... builder) { - for (int i = 0; i < builder.length; i++) { - this.traversal.where((GraphTraversal<Vertex, Vertex>) builder[i].getQuery()); - stepIndex++; - } - - return this; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<E> or(QueryBuilder... builder) { - GraphTraversal<Vertex, Vertex>[] traversals = new GraphTraversal[builder.length]; - for (int i = 0; i < builder.length; i++) { - traversals[i] = (GraphTraversal<Vertex, Vertex>) builder[i].getQuery(); - } - this.traversal.or(traversals); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> store(String name) { - - this.traversal.store(name); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> cap(String name) { - this.traversal.cap(name); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> unfold() { - this.traversal.unfold(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> dedup() { - - this.traversal.dedup(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> emit() { - - this.traversal.emit(); - stepIndex++; - - return this; - - } - - @Override - public QueryBuilder<E> repeat(QueryBuilder<E> builder) { - - this.traversal.repeat((GraphTraversal<Vertex, E>) builder.getQuery()); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> until(QueryBuilder<E> builder) { - this.traversal.until((GraphTraversal<Vertex, E>) builder.getQuery()); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> groupCount() { - this.traversal.groupCount(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> both() { - this.traversal.both(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<Tree> tree() { - - this.traversal.tree(); - stepIndex++; - - return (QueryBuilder<Tree>) this; - } - - @Override - public QueryBuilder<E> by(String name) { - this.traversal.by(name); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> valueMap() { - this.traversal.valueMap(); - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> valueMap(String... names) { - this.traversal.valueMap(names); - stepIndex++; - - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public QueryBuilder<E> simplePath() { - this.traversal.simplePath(); - stepIndex++; - return this; - } - - /** - * {@inheritDoc} - */ - @Override - public QueryBuilder<Path> path() { - this.traversal.path(); - stepIndex++; - return (QueryBuilder<Path>) this; - } - - @Override - public QueryBuilder<Edge> outE() { - this.traversal.outE(); - stepIndex++; - return (QueryBuilder<Edge>) this; - } - - @Override - public QueryBuilder<Edge> inE() { - this.traversal.inE(); - stepIndex++; - return (QueryBuilder<Edge>) this; - } - - @Override - public QueryBuilder<Vertex> outV() { - this.traversal.outV(); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - @Override - public QueryBuilder<Vertex> inV() { - this.traversal.inV(); - stepIndex++; - return (QueryBuilder<Vertex>) this; - } - - @Override - public QueryBuilder<E> as(String name) { - this.traversal.as(name); - - stepIndex++; - return this; - } - - @Override - public QueryBuilder<E> not(QueryBuilder<E> builder) { - this.traversal.not(builder.getQuery()); - - stepIndex++; - return this; - } - - @Override - public QueryBuilder<E> select(String name) { - this.traversal.select(name); - - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> select(Pop pop, String name) { - this.traversal.select(pop, name); - - stepIndex++; - - return this; - } - - @Override - public QueryBuilder<E> 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<String> 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<String, EdgeRule> 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<String> inLabels = new ArrayList<>(); - final List<String> 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<String> 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<String, EdgeRule> 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<String> inLabels = new ArrayList<>(); - final List<String> 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<E> limit(long amount) { - traversal.limit(amount); - return this; - } - - /** - * @{inheritDoc} - */ - @Override - public <E2> E2 getQuery() { - return (E2) this.traversal; - } - - /** - * @{inheritDoc} - */ - @Override - public QueryBuilder<E> getParentQuery() { - return this.parentQuery != null - ? this.parentQuery - : cloneQueryAtStep(parentStepIndex); - } - - @Override - public QueryBuilder<E> 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<E> removeQueryStepsBetween(int start, int end); - - protected void executeQuery() { - - Admin<Vertex, Vertex> admin; - if (start != null) { - this.completeTraversal = traversal.asAdmin(); - } else { - boolean queryLoggingEnabled = false; - if(queryLoggingEnabled) { - String query = groovyTranslator.translate(traversal.asAdmin().getBytecode()); - LOGGER.info("Query: {}", query); - } - - admin = source.V().asAdmin(); - TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin); - - this.completeTraversal = (Admin<Vertex, E>) 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<E> toList() { - if (this.completeTraversal == null) { - executeQuery(); - } - return this.completeTraversal.toList(); - } - - @Override - public QueryBuilder<E> sort(Sort sort) { - Order order = sort.getDirection() == Sort.Direction.ASC ? Order.asc : Order.desc; - traversal.order().by(sort.getProperty(), order); - stepIndex++; - return this; - } - - public PaginationResult<E> toPaginationResult(Pageable pageable) { - int page = pageable.getPage(); - int pageSize = pageable.getPageSize(); - if(pageable.isIncludeTotalCount()) { - return paginateWithTotalCount(page, pageSize); - } else { - return paginateWithoutTotalCount(page, pageSize); - } - } - - private PaginationResult<E> paginateWithoutTotalCount(int page, int pageSize) { - int startIndex = page * pageSize; - traversal.range(startIndex, startIndex + pageSize); - - if (this.completeTraversal == null) { - executeQuery(); - } - return new PaginationResult<E>(completeTraversal.toList()); - } - - private PaginationResult<E> paginateWithTotalCount(int page, int pageSize) { + @Override + public QueryBuilder<E> valueMap() { + this.traversal.valueMap(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> valueMap(String... names) { + this.traversal.valueMap(names); + stepIndex++; + + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public QueryBuilder<E> simplePath() { + this.traversal.simplePath(); + stepIndex++; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public QueryBuilder<Path> path() { + this.traversal.path(); + stepIndex++; + return (QueryBuilder<Path>) this; + } + + @Override + public QueryBuilder<Edge> outE() { + this.traversal.outE(); + stepIndex++; + return (QueryBuilder<Edge>) this; + } + + @Override + public QueryBuilder<Edge> inE() { + this.traversal.inE(); + stepIndex++; + return (QueryBuilder<Edge>) this; + } + + @Override + public QueryBuilder<Vertex> outV() { + this.traversal.outV(); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + @Override + public QueryBuilder<Vertex> inV() { + this.traversal.inV(); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + @Override + public QueryBuilder<E> as(String name) { + this.traversal.as(name); + + stepIndex++; + return this; + } + + @Override + public QueryBuilder<E> not(QueryBuilder<E> builder) { + this.traversal.not(builder.getQuery()); + + stepIndex++; + return this; + } + + @Override + public QueryBuilder<E> select(String name) { + this.traversal.select(name); + + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> select(Pop pop, String name) { + this.traversal.select(pop, name); + + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> 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<String> 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<String, EdgeRule> 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<String> inLabels = new ArrayList<>(); + final List<String> 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<String> 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<String, EdgeRule> 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<String> inLabels = new ArrayList<>(); + final List<String> 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<E> limit(long amount) { + traversal.limit(amount); + return this; + } + + /** + * @{inheritDoc} + */ + @Override + public <E2> E2 getQuery() { + return (E2) this.traversal; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<E> getParentQuery() { + return this.parentQuery != null + ? this.parentQuery + : cloneQueryAtStep(parentStepIndex); + } + + @Override + public QueryBuilder<E> 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<E> removeQueryStepsBetween(int start, int end); + + protected void executeQuery() { + + Admin<Vertex, Vertex> admin; + if (start != null) { + this.completeTraversal = traversal.asAdmin(); + } else { + boolean queryLoggingEnabled = false; + if(queryLoggingEnabled) { + String query = groovyTranslator.translate(traversal.asAdmin().getBytecode()); + LOGGER.info("Query: {}", query); + } + + admin = source.V().asAdmin(); + TraversalHelper.insertTraversal(admin.getEndStep(), traversal.asAdmin(), admin); + + this.completeTraversal = (Admin<Vertex, E>) 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<E> toList() { + if (this.completeTraversal == null) { + executeQuery(); + } + return this.completeTraversal.toList(); + } + + @Override + public QueryBuilder<E> sort(Sort sort) { + Order order = sort.getDirection() == Sort.Direction.ASC ? Order.asc : Order.desc; + traversal.order().by(sort.getProperty(), order); + stepIndex++; + return this; + } + + public PaginationResult<E> toPaginationResult(Pageable pageable) { + int page = pageable.getPage(); + int pageSize = pageable.getPageSize(); + if(pageable.isIncludeTotalCount()) { + return paginateWithTotalCount(page, pageSize); + } else { + return paginateWithoutTotalCount(page, pageSize); + } + } + + private PaginationResult<E> paginateWithoutTotalCount(int page, int pageSize) { + int startIndex = page * pageSize; + traversal.range(startIndex, startIndex + pageSize); + + if (this.completeTraversal == null) { + executeQuery(); + } + return completeTraversal.hasNext() + ? new PaginationResult<E>(completeTraversal.toList()) + : new PaginationResult<E>(Collections.emptyList()); + } + + private PaginationResult<E> paginateWithTotalCount(int page, int pageSize) { int startIndex = page * pageSize; traversal.fold().as("results","count") .select("results","count"). @@ -1023,45 +1025,50 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { if (this.completeTraversal == null) { executeQuery(); } - return mapPaginationResult((Map<String,Object>) completeTraversal.next()); - } - - private PaginationResult<E> mapPaginationResult(Map<String,Object> result) { - Object objCount = result.get("count"); - Object vertices = result.get("results"); - if(vertices == null) { - return new PaginationResult<E>(Collections.emptyList() ,0L); - } - List<E> results = null; - if(vertices instanceof List) { - results = (List<E>) vertices; - } else if (vertices instanceof Vertex) { - results = Collections.singletonList((E) vertices); - } else { - String msg = String.format("Results must be a list or a vertex, but was %s", vertices.getClass().getName()); - LOGGER.error(msg); - throw new IllegalArgumentException(msg); - } - long totalCount = parseCount(objCount); - return new PaginationResult<E>(results, totalCount); - } - - private long parseCount(Object count) { - if(count instanceof String) { - return Long.parseLong((String) count); - } else if(count instanceof Integer) { - return Long.valueOf((int) count); - } else if (count instanceof Long) { - return (long) count; - } else { - throw new IllegalArgumentException("Count must be a string, integer, or long"); + try { + return mapPaginationResult((Map<String,Object>) completeTraversal.next()); + // .next() will throw an IllegalArguementException if there are no vertices of the given type + } catch (IllegalArgumentException e) { + return new PaginationResult<>(Collections.emptyList(), 0L); } - } - - protected QueryBuilder<Edge> has(String key, String value) { - traversal.has(key, value); - - return (QueryBuilder<Edge>) this; - } - -} + } + + private PaginationResult<E> mapPaginationResult(Map<String,Object> result) { + Object objCount = result.get("count"); + Object vertices = result.get("results"); + if(vertices == null) { + return new PaginationResult<E>(Collections.emptyList() ,0L); + } + List<E> results = null; + if(vertices instanceof List) { + results = (List<E>) vertices; + } else if (vertices instanceof Vertex) { + results = Collections.singletonList((E) vertices); + } else { + String msg = String.format("Results must be a list or a vertex, but was %s", vertices.getClass().getName()); + LOGGER.error(msg); + throw new IllegalArgumentException(msg); + } + long totalCount = parseCount(objCount); + return new PaginationResult<E>(results, totalCount); + } + + private long parseCount(Object count) { + if(count instanceof String) { + return Long.parseLong((String) count); + } else if(count instanceof Integer) { + return Long.valueOf((int) count); + } else if (count instanceof Long) { + return (long) count; + } else { + throw new IllegalArgumentException("Count must be a string, integer, or long"); + } + } + + protected QueryBuilder<Edge> has(String key, String value) { + traversal.has(key, value); + + return (QueryBuilder<Edge>) this; + } + + } diff --git a/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java b/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java index 3bf991ec..39539988 100644 --- a/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java +++ b/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java @@ -20,1002 +20,1021 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.rest.db; - -import static org.onap.aai.edges.enums.AAIDirection.NONE; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Collections; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonMappingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.core.UriInfo; - -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.structure.Edge; -import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.javatuples.Pair; -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.FixMethodOrder; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.MethodSorters; -import org.junit.runners.Parameterized; -import org.mockito.Mockito; -import org.onap.aai.AAISetup; -import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.edges.enums.EdgeField; -import org.onap.aai.edges.enums.EdgeProperty; -import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.Introspector; -import org.onap.aai.introspection.Loader; -import org.onap.aai.introspection.ModelType; -import org.onap.aai.parsers.query.QueryParser; -import org.onap.aai.prevalidation.ValidationService; -import org.onap.aai.query.builder.Pageable; -import org.onap.aai.query.builder.QueryOptions; -import org.onap.aai.query.builder.Sort; -import org.onap.aai.query.builder.Sort.Direction; -import org.onap.aai.rest.db.responses.ErrorResponse; -import org.onap.aai.rest.db.responses.Relationship; -import org.onap.aai.rest.db.responses.RelationshipWrapper; -import org.onap.aai.rest.db.responses.ServiceException; -import org.onap.aai.rest.ueb.UEBNotification; -import org.onap.aai.restcore.HttpMethod; -import org.onap.aai.serialization.engines.QueryStyle; -import org.onap.aai.serialization.engines.TransactionalGraphEngine; -import org.onap.aai.util.AAIConfig; -import org.skyscreamer.jsonassert.JSONAssert; -import org.skyscreamer.jsonassert.JSONCompareMode; -import org.skyscreamer.jsonassert.comparator.JSONComparator; -import org.springframework.boot.test.mock.mockito.MockBean; - -@RunWith(value = Parameterized.class) -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class HttpEntryTest extends AAISetup { - - @MockBean ValidationService validationService; - - protected static final MediaType APPLICATION_JSON = MediaType.valueOf("application/json"); - - private static final Set<Integer> VALID_HTTP_STATUS_CODES = new HashSet<>(); - - static { - VALID_HTTP_STATUS_CODES.add(200); - VALID_HTTP_STATUS_CODES.add(201); - VALID_HTTP_STATUS_CODES.add(204); - } - - @Parameterized.Parameter(value = 0) - public QueryStyle queryStyle; - - /* - * TODO Change the HttpEntry instances accoringly - */ - @Parameterized.Parameters(name = "QueryStyle.{0}") - public static Collection<Object[]> data() { - return Arrays.asList(new Object[][] { { QueryStyle.TRAVERSAL }, { QueryStyle.TRAVERSAL_URI } }); - } - - private Loader loader; - private TransactionalGraphEngine dbEngine; - private GraphTraversalSource traversal; - - private HttpHeaders httpHeaders; - - private UriInfo uriInfo; - - private MultivaluedMap<String, String> headersMultiMap; - private MultivaluedMap<String, String> queryParameters; - - private List<String> aaiRequestContextList; - - private List<MediaType> outputMediaTypes; - - ObjectMapper mapper = new ObjectMapper(); - - @Before - public void setup() { - - httpHeaders = Mockito.mock(HttpHeaders.class); - uriInfo = Mockito.mock(UriInfo.class); - - headersMultiMap = new MultivaluedHashMap<>(); - queryParameters = Mockito.spy(new MultivaluedHashMap<>()); - - headersMultiMap.add("X-FromAppId", "JUNIT"); - headersMultiMap.add("X-TransactionId", UUID.randomUUID().toString()); - headersMultiMap.add("Real-Time", "true"); - headersMultiMap.add("Accept", "application/json"); - headersMultiMap.add("aai-request-context", ""); - - outputMediaTypes = new ArrayList<>(); - outputMediaTypes.add(APPLICATION_JSON); - - aaiRequestContextList = new ArrayList<>(); - aaiRequestContextList.add(""); - - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); - loader = traversalHttpEntry.getLoader(); - dbEngine = traversalHttpEntry.getDbEngine(); - traversal = dbEngine.tx().traversal(); - - when(httpHeaders.getAcceptableMediaTypes()).thenReturn(outputMediaTypes); - when(httpHeaders.getRequestHeaders()).thenReturn(headersMultiMap); - - when(httpHeaders.getRequestHeader("aai-request-context")).thenReturn(aaiRequestContextList); - - when(uriInfo.getQueryParameters()).thenReturn(queryParameters); - when(uriInfo.getQueryParameters(false)).thenReturn(queryParameters); - - // TODO - Check if this is valid since RemoveDME2QueryParameters seems to be - // very unreasonable - Mockito.doReturn(null).when(queryParameters).remove(any()); - - when(httpHeaders.getMediaType()).thenReturn(APPLICATION_JSON); - } - - @After - public void rollback() { - dbEngine.rollback(); - } - - @Test - public void thatObjectCanBeRetrieved() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("equip-type", "theEquipType") - .property(AAIProperties.AAI_URI, uri) - .next(); - - JSONObject expectedResponseBody = new JSONObject() - .put("hostname", "theHostname") - .put("equip-type", "theEquipType"); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); - JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); - - JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); - assertEquals("Expected the pserver to be returned", 200, response.getStatus()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("equip-type", "theEquipType") - .property(AAIProperties.AAI_URI, uri) - .next(); - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname2") - .property("equip-type", "theEquipType2") - .property(AAIProperties.AAI_URI, uri + "2") - .next(); - - JSONObject expectedResponseBody = new JSONObject(); - JSONObject pserver1 = new JSONObject() - .put("hostname", "theHostname") - .put("equip-type", "theEquipType"); - JSONObject pserver2 = new JSONObject() - .put("hostname", "theHostname2") - .put("equip-type", "theEquipType2"); - expectedResponseBody.put("pserver", new JSONArray() - .put(pserver1) - .put(pserver2)); - - uri = "/cloud-infrastructure/pservers"; - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); - JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); - - JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); - assertEquals("Expected the pservers to be returned", 200, response.getStatus()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatPaginatedObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("equip-type", "theEquipType") - .property(AAIProperties.AAI_URI, uri) - .next(); - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname2") - .property("equip-type", "theEquipType2") - .property(AAIProperties.AAI_URI, uri + "2") - .next(); - - JSONObject expectedResponseBody = new JSONObject(); - JSONObject pserver1 = new JSONObject() - .put("hostname", "theHostname") - .put("equip-type", "theEquipType"); - expectedResponseBody.put("pserver", new JSONArray() - .put(pserver1)); - - uri = "/cloud-infrastructure/pservers"; - QueryOptions queryOptions = QueryOptions.builder().pageable(new Pageable(1, 1)).build(); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); - JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); - - assertNull(response.getHeaderString("total-results")); - assertEquals(1, actualResponseBody.getJSONArray("pserver").length()); - assertEquals("Expected the pservers to be returned", 200, response.getStatus()); - verify(validationService, times(1)).validate(any()); - - queryOptions = QueryOptions.builder().pageable(new Pageable(0,5).includeTotalCount()).build(); - response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); - actualResponseBody = new JSONObject(response.getEntity().toString()); - assertEquals(2, actualResponseBody.getJSONArray("pserver").length()); - } - - @Test - public void thatPagationResultWithTotalCountCanBeRetrieved() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("equip-type", "theEquipType") - .property(AAIProperties.AAI_URI, uri) - .next(); - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname2") - .property("equip-type", "theEquipType2") - .property(AAIProperties.AAI_URI, uri + "2") - .next(); - - JSONObject expectedResponseBody = new JSONObject(); - JSONObject pserver1 = new JSONObject() - .put("hostname", "theHostname") - .put("equip-type", "theEquipType"); - expectedResponseBody.put("pserver", new JSONArray() - .put(pserver1)); - - uri = "/cloud-infrastructure/pservers"; - QueryOptions queryOptions = QueryOptions.builder().pageable(new Pageable(1, 1).includeTotalCount()).build(); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); - JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); - String totalCount = response.getHeaderString("total-results"); - String totalPages = response.getHeaderString("total-pages"); - - assertEquals(2, Integer.parseInt(totalCount)); - assertEquals(2, Integer.parseInt(totalPages)); - assertEquals(1, actualResponseBody.getJSONArray("pserver").length()); - assertEquals("Expected the pservers to be returned", 200, response.getStatus()); - verify(validationService, times(1)).validate(any()); - - queryOptions = QueryOptions.builder().pageable(new Pageable(0, 2)).build(); - response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); - actualResponseBody = new JSONObject(response.getEntity().toString()); - assertEquals(2, actualResponseBody.getJSONArray("pserver").length()); - } - - @Test - public void thatSortedObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("equip-type", "theEquipType") - .property(AAIProperties.AAI_URI, uri) - .next(); - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname2") - .property("equip-type", "theEquipType2") - .property(AAIProperties.AAI_URI, uri + "2") - .next(); - - JSONObject expectedResponseBody = new JSONObject(); - JSONObject pserver1 = new JSONObject() - .put("hostname", "theHostname") - .put("equip-type", "theEquipType"); - JSONObject pserver2 = new JSONObject() - .put("hostname", "theHostname2") - .put("equip-type", "theEquipType2"); - expectedResponseBody.put("pserver", new JSONArray() - .put(pserver1).put(pserver2)); - - // ascending - uri = "/cloud-infrastructure/pservers"; - QueryOptions queryOptions = QueryOptions.builder().sort(Sort.builder().property("equip-type").direction(Direction.ASC).build()).build(); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); - JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); - assertEquals("theEquipType", actualResponseBody.getJSONArray("pserver").getJSONObject(0).getString("equip-type")); - assertEquals("theEquipType2", actualResponseBody.getJSONArray("pserver").getJSONObject(1).getString("equip-type")); - - // descending - queryOptions = QueryOptions.builder().sort(Sort.builder().property("equip-type").direction(Direction.DESC).build()).build(); - response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); - actualResponseBody = new JSONObject(response.getEntity().toString()); - assertEquals("theEquipType2", actualResponseBody.getJSONArray("pserver").getJSONObject(0).getString("equip-type")); - assertEquals("theEquipType", actualResponseBody.getJSONArray("pserver").getJSONObject(1).getString("equip-type")); - - } - - @Test - public void thatObjectsCanNotBeFound() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/junit-test2"; - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); - assertEquals("The pserver is not found", 404, response.getStatus()); - } - - @Test - public void thatObjectCanBeCreatedViaPUT() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - String requestBody = new JSONObject().put("hostname", "theHostname").toString(); - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); - assertEquals("Expecting the pserver to be created", 201, response.getStatus()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatObjectCreationFailsWhenResourceVersionIsProvided() - throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - String requestBody = new JSONObject() - .put("hostname", "theHostname") - .put("resource-version", "123") - .toString(); - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); - ErrorResponse errorResponseEntity = mapper.readValue(response.getEntity().toString(), ErrorResponse.class); - assertEquals("Expecting the pserver to be created", 412, response.getStatus()); - assertEquals( - "Resource version specified on create:resource-version passed for create of /cloud-infrastructure/pservers/pserver/theHostname", - errorResponseEntity.getRequestError().getServiceException().getVariables().get(2)); - } - - @Test - public void thatObjectCanBeUpdatedViaPUT() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("number-of-cpus", "10") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .next(); - String requestBody = new JSONObject() - .put("hostname", "updatedHostname") - .put("resource-version", "123") - .toString(); - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); - assertEquals("Expecting the pserver to be updated", 200, response.getStatus()); - assertTrue("That old properties are removed", - traversal.V().has("hostname", "updatedHostname").hasNot("number-of-cpus").hasNext()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatUpdateFailsWhenResourceVersionsMismatch() - throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .next(); - String requestBody = new JSONObject() - .put("hostname", "updatedHostname") - .put("resource-version", "456") - .toString(); - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); - ErrorResponse errorResponseEntity = mapper.readValue(response.getEntity().toString(), ErrorResponse.class); - assertEquals("Expecting the update to fail", 412, response.getStatus()); - assertEquals( - "Precondition Failed:resource-version MISMATCH for update of /cloud-infrastructure/pservers/pserver/updatedHostname", - errorResponseEntity.getRequestError().getServiceException().getVariables().get(2)); - } - - @Test - public void thatUpdateFailsWhenResourceVersionIsNotProvided() - throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("in-maint", "false") - .property(AAIProperties.AAI_URI, uri) - .next(); - - String requestBody = new JSONObject() - .put("hostname", "theHostname") - .put("is-maint", "true") - .toString(); - - doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); - ErrorResponse errorResponseEntity = mapper.readValue(response.getEntity().toString(), ErrorResponse.class); - assertEquals("Request should fail when no resource-version is provided", 412, response.getStatus()); - assertEquals( - "Precondition Required:resource-version not passed for update of /cloud-infrastructure/pservers/pserver/theHostname", - errorResponseEntity.getRequestError().getServiceException().getVariables().get(2)); - } - - @Test - public void thatCreateViaPUTAddsRelationshipsToExistingObjects() throws UnsupportedEncodingException, AAIException { - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "hostname") - .property(AAIProperties.AAI_URI, "/cloud-infrastructure/pservers/pserver/hostname") - .next(); - String uri = "/cloud-infrastructure/pservers/pserver/hostname/p-interfaces/p-interface/p1"; - String requestBody = new JSONObject().put("interface-name", "p1").toString(); - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); - assertEquals("response is successful", 201, response.getStatus()); - assertTrue("p-interface was created", - traversal.V().has("aai-node-type", "p-interface").has("interface-name", "p1").hasNext()); - assertTrue("p-interface has outgoing edge to p-server", - traversal.V().has("aai-node-type", "p-interface").has("aai-uri", uri).has("interface-name", "p1") - .out("tosca.relationships.network.BindsTo").has("aai-node-type", "pserver") - .has("hostname", "hostname").hasNext()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatObjectsCanBePatched() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/the-hostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "the-hostname") - .property("equip-type", "the-equip-type") - .property(AAIProperties.AAI_URI, uri) - .next(); - String requestBody = new JSONObject() - .put("hostname", "new-hostname") - .toString(); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.MERGE_PATCH, uri, requestBody); - assertEquals("Expected the pserver to be updated", 200, response.getStatus()); - assertTrue("object should be updated while keeping old properties", - traversal.V().has("aai-node-type", "pserver").has("hostname", "new-hostname") - .has("equip-type", "the-equip-type").hasNext()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatObjectsCanBeDeleted() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/the-hostname"; - String resourceVersion = "123"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "the-hostname") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, resourceVersion) - .next(); - assertEquals("Expecting a No Content response", 204, - doDelete(resourceVersion, uri, "pserver").getStatus()); - assertTrue("Expecting the pserver to be deleted", - !traversal.V().has("aai-node-type", "pserver").has("hostname", "the-hostname").hasNext()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatRelationshipCanBeCreated() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/edge-test-pserver"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "edge-test-pserver") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .next(); - uri = "/cloud-infrastructure/complexes/complex/edge-test-complex"; - traversal.addV() - .property("aai-node-type", "complex") - .property("physical-location-id", "edge-test-complex") - .property("physical-location-type", "AAIDefault") - .property("street1", "AAIDefault") - .property("city", "AAIDefault") - .property("postal-code", "07748") - .property("country", "USA") - .property("region", "US") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "234") - .next(); - - uri = "/cloud-infrastructure/complexes/complex/edge-test-complex/relationship-list/relationship"; - String requestBody = new JSONObject() - .put("related-to", "pserver") - .put("related-link", - String.format("/aai/%s/cloud-infrastructure/pservers/pserver/edge-test-pserver", - schemaVersions.getDefaultVersion().toString())) - .put("relationship-label", "org.onap.relationships.inventory.LocatedIn") - .toString(); - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, requestBody); - assertEquals("Expected the pserver relationship to be created", 200, response.getStatus()); - GraphTraversal<Vertex, Vertex> vertexQuery = traversal.V() - .has("aai-node-type", "complex") - .has("physical-location-id", "edge-test-complex") - .in("org.onap.relationships.inventory.LocatedIn") - .has("aai-node-type", "pserver") - .has("hostname", "edge-test-pserver"); - GraphTraversal<Edge, Edge> edgeQuery = traversal.E() - .has(EdgeField.PRIVATE.toString(), "false") - .has(EdgeProperty.CONTAINS.toString(), NONE.toString()) - .has(EdgeProperty.DELETE_OTHER_V.toString(), NONE.toString()) - .has(EdgeProperty.PREVENT_DELETE.toString(), "IN"); - assertTrue("p-server has incoming edge from complex", vertexQuery.hasNext()); - assertTrue("Created Edge has expected properties", edgeQuery.hasNext()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatRelationshipCanNotBeCreatedEdgeMultiplicity() - throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { - String uri = "/cloud-infrastructure/pservers/pserver/httpEntryTest-pserver-01"; - traversal - .addV() // pserver - .property("aai-node-type", "pserver") - .property("hostname", "httpEntryTest-pserver-01") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .as("v1") - .addV() // complex - .property("aai-node-type", "complex") - .property("physical-location-id", "httpEntryTest-complex-01") - .property("physical-location-type", "AAIDefault") - .property("street1", "AAIDefault") - .property("city", "AAIDefault") - .property("postal-code", "07748") - .property("country", "USA") - .property("region", "US") - .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/httpEntryTest-complex-01") - .property(AAIProperties.RESOURCE_VERSION, "234") - .as("v2") - // edge between pserver and complex - .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") - .next(); - - // Put Relationship - uri = "/cloud-infrastructure/pservers/pserver/httpEntryTest-pserver-01/relationship-list/relationship"; - String requestBody = new JSONObject() - .put("related-to", "complex") - .put("related-link", - String.format("/aai/%s/cloud-infrastructure/complexes/complex/httpEntryTest-complex-01", - schemaVersions.getDefaultVersion().toString())) - .put("relationship-label", "org.onap.relationships.inventory.LocatedIn") - .toString(); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, requestBody); - ServiceException serviceException = mapper.readValue(response.getEntity().toString(), ErrorResponse.class) - .getRequestError().getServiceException(); - - assertEquals("Expected the response code to be Bad Request", 400, response.getStatus()); - assertEquals("ERR.5.4.6140", serviceException.getVariables().get(3)); - assertEquals( - "Edge multiplicity violated:multiplicity rule violated: only one edge can exist with label: org.onap.relationships.inventory.LocatedIn between pserver and complex", - serviceException.getVariables().get(2)); - } - - @Test - public void putEdgeWrongLabelTest() - throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { - String uri = "/cloud-infrastructure/pservers/pserver/edge-test-pserver"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "edge-test-pserver") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .next(); - uri = "/cloud-infrastructure/complexes/complex/edge-test-complex"; - traversal.addV() - .property("aai-node-type", "complex") - .property("physical-location-id", "edge-test-complex") - .property("physical-location-type", "AAIDefault") - .property("street1", "AAIDefault") - .property("city", "AAIDefault") - .property("postal-code", "07748") - .property("country", "USA") - .property("region", "US") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "234") - .next(); - - uri = "/cloud-infrastructure/complexes/complex/edge-test-complex/relationship-list/relationship"; - String requestBody = new JSONObject() - .put("related-to", "pserver") - .put("related-link", - String.format("/aai/%s/cloud-infrastructure/pservers/pserver/edge-test-pserver", - schemaVersions.getDefaultVersion().toString())) - .put("relationship-label", "does.not.exist") - .toString(); - - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, requestBody); - ServiceException serviceException = mapper.readValue(response.getEntity().toString(), ErrorResponse.class) - .getRequestError().getServiceException(); - - assertEquals("Expected the pserver to be created", 400, response.getStatus()); - assertEquals("ERR.5.4.6107", serviceException.getVariables().get(3)); - assertEquals( - "Required Edge-property not found in input data:org.onap.aai.edges.exceptions.EdgeRuleNotFoundException: No rule found for EdgeRuleQuery with filter params node type: complex, node type: pserver, label: does.not.exist, type: COUSIN, isPrivate: false.", - serviceException.getVariables().get(2)); - } - - @Test - public void thatObjectsCanBeRetrievedInPathedResponseFormat() throws UnsupportedEncodingException, AAIException { - traversal - .addV() // pserver - .property("aai-node-type", "pserver") - .property("hostname", "pserver-1") - .property(AAIProperties.AAI_URI, "/cloud-infrastructure/pservers/pserver/pserver-1") - .property(AAIProperties.RESOURCE_VERSION, "123") - .addV() // pserver - .property("aai-node-type", "pserver") - .property("hostname", "pserver-2") - .property(AAIProperties.AAI_URI, "/cloud-infrastructure/pservers/pserver/pserver-2") - .property(AAIProperties.RESOURCE_VERSION, "234") - .next(); - - queryParameters.add("format", "pathed"); - String requestBody = ""; - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, - "/cloud-infrastructure/pservers"); - queryParameters.remove("format"); - - String responseEntity = response.getEntity().toString(); - assertEquals("Expected get to succeed", 200, response.getStatus()); - assertThat(responseEntity, containsString("/cloud-infrastructure/pservers/pserver/pserver-1")); - assertThat(responseEntity, containsString("/cloud-infrastructure/pservers/pserver/pserver-2")); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void thatRelatedObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; - traversal - .addV() // pserver - .property("aai-node-type", "pserver") - .property("hostname", "related-to-pserver") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .as("v1") - .addV() // complex - .property("aai-node-type", "complex") - .property("physical-location-id", "related-to-complex") - .property("physical-location-type", "AAIDefault") - .property("street1", "AAIDefault") - .property("city", "AAIDefault") - .property("postal-code", "07748") - .property("country", "USA") - .property("region", "US") - .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/related-to-complex") - .property(AAIProperties.RESOURCE_VERSION, "234") - .as("v2") - // edge between pserver and complex - .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") - .next(); - - uri = "/cloud-infrastructure/complexes/complex/related-to-complex/related-to/pservers"; - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); - - assertEquals("Expected the response to be successful", 200, response.getStatus()); - assertThat("Related pserver is returned", response.getEntity().toString(), - containsString("\"hostname\":\"related-to-pserver\"")); - verify(validationService, times(1)).validate(any()); - - } - - @Test - public void getAbstractTest() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/abstract-pserver"; - traversal - .addV() // pserver - .property("aai-node-type", "pserver") - .property("hostname", "abstract-pserver") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .as("v1") - .addV() // generic-vnf - .property("aai-node-type", "generic-vnf") - .property("vnf-id", "abstract-generic-vnf") - .property("vnf-name", "the-vnf-name") - .property(AAIProperties.AAI_URI, "/network/generic-vnfs/generic-vnf/abstract-generic-vnf") - .property(AAIProperties.RESOURCE_VERSION, "234") - .as("v2") - // edge between pserver and generic-vnf - .addE("tosca.relationships.HostedOn").from("v2").to("v1") - .next(); - - uri = "/network/generic-vnfs/generic-vnf/abstract-generic-vnf/related-to/pservers"; - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); - assertThat("Related to pserver is returned.", response.getEntity().toString(), - containsString("\"hostname\":\"abstract-pserver\"")); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void getRelationshipListTest() - throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { - String uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; - traversal - .addV() // pserver - .property("aai-node-type", "pserver") - .property("hostname", "related-to-pserver") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .as("v1") - .addV() // complex - .property("aai-node-type", "complex") - .property("physical-location-id", "related-to-complex") - .property("physical-location-type", "AAIDefault") - .property("street1", "AAIDefault") - .property("city", "AAIDefault") - .property("postal-code", "07748") - .property("country", "USA") - .property("region", "US") - .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/related-to-complex") - .property(AAIProperties.RESOURCE_VERSION, "234") - .as("v2") - // edge between pserver and complex - .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") - // these properties are required when finding related edges - .property(EdgeProperty.CONTAINS.toString(), NONE.toString()) - .property(EdgeField.PRIVATE.toString(), "false") - .next(); - - // Get Relationship - uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET_RELATIONSHIP, uri); - Relationship[] relationships = mapper.readValue(response.getEntity().toString(), RelationshipWrapper.class) - .getRelationships(); - - assertEquals("complex", relationships[0].getRelatedTo()); - assertEquals("org.onap.relationships.inventory.LocatedIn", relationships[0].getRelationshipLabel()); - assertEquals("/aai/v14/cloud-infrastructure/complexes/complex/related-to-complex", - relationships[0].getRelatedLink()); - assertEquals("complex.physical-location-id", relationships[0].getRelationshipData()[0].getRelationshipKey()); - assertEquals("related-to-complex", relationships[0].getRelationshipData()[0].getRelationshipValue()); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void getRelationshipListTestWithFormatSimple() throws UnsupportedEncodingException, AAIException { - String uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; - traversal - .addV() // pserver - .property("aai-node-type", "pserver") - .property("hostname", "related-to-pserver") - .property(AAIProperties.AAI_URI, uri) - .property(AAIProperties.RESOURCE_VERSION, "123") - .as("v1") - .addV() // complex - .property("aai-node-type", "complex") - .property("physical-location-id", "related-to-complex") - .property("physical-location-type", "AAIDefault") - .property("street1", "AAIDefault") - .property("city", "AAIDefault") - .property("postal-code", "07748") - .property("country", "USA") - .property("region", "US") - .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/related-to-complex") - .property(AAIProperties.RESOURCE_VERSION, "234") - .as("v2") - // edge between pserver and complex - .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") - // these properties are required when finding related edges - .property(EdgeProperty.CONTAINS.toString(), NONE.toString()) - .property(EdgeField.PRIVATE.toString(), "false") - .next(); - - // Get Relationship - uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; - queryParameters.add("format", "resource"); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET_RELATIONSHIP, uri); - - JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); - - // Define the expected response - JSONObject relationshipData = new JSONObject().put("relationship-key", "complex.physical-location-id") - .put("relationship-value", "related-to-complex"); - JSONObject relationship = new JSONObject() - .put("related-to", "complex") - .put("relationship-label", "org.onap.relationships.inventory.LocatedIn") - .put("related-link", - String.format("/aai/%s/cloud-infrastructure/complexes/complex/related-to-complex", - schemaVersions.getDefaultVersion())) - .put("relationship-data", new JSONArray().put(relationshipData)); - JSONObject pserver = new JSONObject() - .put("hostname", "related-to-pserver") - .put("resource-version", "123") - .put("relationship-list", new JSONObject().put("relationship", new JSONArray().put(relationship))); - JSONObject expectedResponseBody = new JSONObject() - .put("results", new JSONArray().put(new JSONObject().put("pserver", pserver))); - - JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); - queryParameters.remove("format"); - verify(validationService, times(1)).validate(any()); - } - - @Test - public void notificationOnRelatedToTest() throws UnsupportedEncodingException, AAIException { - - Loader ld = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); - UEBNotification uebNotification = Mockito.spy(new UEBNotification(ld, loaderFactory, schemaVersions)); - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), uebNotification); - - Loader loader = traversalHttpEntry.getLoader(); - TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); - // Put pserver - String uri = "/cloud-infrastructure/pservers/pserver/junit-edge-test-pserver"; - String content = "{\"hostname\":\"junit-edge-test-pserver\"}"; - doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, content); - // Put complex - uri = "/cloud-infrastructure/complexes/complex/junit-edge-test-complex"; - content = "{\"physical-location-id\":\"junit-edge-test-complex\",\"physical-location-type\":\"AAIDefault\",\"street1\":\"AAIDefault\",\"city\":\"AAIDefault\",\"state\":\"NJ\",\"postal-code\":\"07748\",\"country\":\"USA\",\"region\":\"US\"}"; - doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, content); - - // PutEdge - uri = "/cloud-infrastructure/complexes/complex/junit-edge-test-complex/relationship-list/relationship"; - content = "{\"related-to\":\"pserver\",\"related-link\":\"/aai/" + schemaVersions.getDefaultVersion().toString() - + "/cloud-infrastructure/pservers/pserver/junit-edge-test-pserver\",\"relationship-label\":\"org.onap.relationships.inventory.LocatedIn\"}"; - - doNothing().when(uebNotification).triggerEvents(); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, content); - - assertEquals("Expected the pserver relationship to be deleted", 200, response.getStatus()); - assertEquals("Two notifications", 2, uebNotification.getEvents().size()); - assertEquals("Notification generated for PUT edge", "UPDATE", - uebNotification.getEvents().get(0).getEventHeader().getValue("action").toString()); - assertThat("Event body for the edge create has the related to", - uebNotification.getEvents().get(0).getObj().marshal(false), - containsString("cloud-infrastructure/pservers/pserver/junit-edge-test-pserver")); - - response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.DELETE_EDGE, uri, content); - assertEquals("Expected the pserver relationship to be deleted", 204, response.getStatus()); - assertEquals("Two notifications", 2, uebNotification.getEvents().size()); - assertEquals("Notification generated for DELETE edge", "UPDATE", - uebNotification.getEvents().get(0).getEventHeader().getValue("action").toString()); - assertThat("Event body for the edge delete does not have the related to", - uebNotification.getEvents().get(0).getObj().marshal(false), - not(containsString("cloud-infrastructure/pservers/pserver/junit-edge-test-pserver"))); - dbEngine.rollback(); - - } - - private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, - String uri) throws UnsupportedEncodingException, AAIException { - return doRequest(httpEntry, loader, dbEngine, method, uri, null, null); - } - - private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, - String uri, String requestBody) throws UnsupportedEncodingException, AAIException { - return doRequest(httpEntry, loader, dbEngine, method, uri, requestBody, null); - } - private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, - String uri, QueryOptions queryOptions) throws UnsupportedEncodingException, AAIException { - return doRequest(httpEntry, loader, dbEngine, method, uri, null, queryOptions); - } - - private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, - String uri, String requestBody, QueryOptions queryOptions) throws UnsupportedEncodingException, AAIException { - URI uriObject = UriBuilder.fromPath(uri).build(); - QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); - String objType; - if (!uriQuery.getContainerType().equals("")) { - objType = uriQuery.getContainerType(); - } else { - objType = uriQuery.getResultType(); - } - if (uri.endsWith("relationship")) { - objType = "relationship"; - } - Introspector obj; - if (method.equals(HttpMethod.GET) || method.equals(HttpMethod.GET_RELATIONSHIP)) { - obj = loader.introspectorFromName(objType); - } else { - obj = loader.unmarshal(objType, requestBody, org.onap.aai.restcore.MediaType.getEnum("application/json")); - } - - DBRequest.Builder builder = new DBRequest.Builder(method, uriObject, uriQuery, obj, httpHeaders, uriInfo, - "JUNIT-TRANSACTION"); - DBRequest dbRequest = requestBody != null - ? builder.rawRequestContent(requestBody).build() - : builder.build(); - - List<DBRequest> dbRequestList = Collections.singletonList(dbRequest); - - Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT", Collections.emptySet(), true, queryOptions); - return responsesTuple.getValue1().get(0).getValue1(); - } - - private Response doDelete(String resourceVersion, String uri, String nodeType) - throws UnsupportedEncodingException, AAIException { - queryParameters.add("resource-version", resourceVersion); - - URI uriObject = UriBuilder.fromPath(uri).build(); - - QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); - - String content = ""; - - Introspector obj = loader.introspectorFromName(nodeType); - - DBRequest dbRequest = new DBRequest.Builder(HttpMethod.DELETE, uriObject, uriQuery, obj, httpHeaders, uriInfo, - "JUNIT-TRANSACTION").rawRequestContent(content).build(); - - Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalHttpEntry.process(Arrays.asList(dbRequest), - "JUNIT"); - return responsesTuple.getValue1().get(0).getValue1(); - } - - @Test - public void setDepthTest() throws AAIException { - System.setProperty("AJSC_HOME", "."); - System.setProperty("BUNDLECONFIG_DIR", "src/main/test/resources"); - - String depthParam = AAIConfig.get("aai.rest.getall.depthparam"); - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); - int depth = traversalHttpEntry.setDepth(null, depthParam); - assertEquals(AAIProperties.MAXIMUM_DEPTH.intValue(), depth); - } - - @Test - public void thatEventsAreValidated() throws AAIException, UnsupportedEncodingException { - String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; - traversal.addV() - .property("aai-node-type", "pserver") - .property("hostname", "theHostname") - .property("equip-type", "theEquipType") - .property(AAIProperties.AAI_URI, uri) - .next(); - - JSONObject expectedResponseBody = new JSONObject() - .put("hostname", "theHostname") - .put("equip-type", "theEquipType"); - Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); - JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); - - JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); - assertEquals("Expected the pserver to be returned", 200, response.getStatus()); - verify(validationService, times(1)).validate(any()); - } -} + package org.onap.aai.rest.db; + + import static org.onap.aai.edges.enums.AAIDirection.NONE; + import static org.hamcrest.Matchers.containsString; + import static org.hamcrest.Matchers.not; + import static org.junit.Assert.assertEquals; + import static org.junit.Assert.assertFalse; + import static org.junit.Assert.assertNull; + import static org.junit.Assert.assertThat; + import static org.junit.Assert.assertTrue; + import static org.mockito.ArgumentMatchers.any; + import static org.mockito.Mockito.doNothing; + import static org.mockito.Mockito.times; + import static org.mockito.Mockito.verify; + import static org.mockito.Mockito.when; + + import java.util.Collections; + import com.fasterxml.jackson.core.JsonProcessingException; + import com.fasterxml.jackson.databind.JsonMappingException; + import com.fasterxml.jackson.databind.ObjectMapper; + import com.google.gson.JsonObject; + import com.google.gson.JsonParser; + + import java.io.UnsupportedEncodingException; + import java.net.URI; + import java.util.ArrayList; + import java.util.Arrays; + import java.util.Collection; + import java.util.HashSet; + import java.util.List; + import java.util.Set; + import java.util.UUID; + + import javax.ws.rs.core.HttpHeaders; + import javax.ws.rs.core.MediaType; + import javax.ws.rs.core.MultivaluedHashMap; + import javax.ws.rs.core.MultivaluedMap; + import javax.ws.rs.core.Response; + import javax.ws.rs.core.UriBuilder; + import javax.ws.rs.core.UriInfo; + + import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; + import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; + import org.apache.tinkerpop.gremlin.structure.Edge; + import org.apache.tinkerpop.gremlin.structure.Vertex; + import org.javatuples.Pair; + import org.json.JSONArray; + import org.json.JSONObject; + import org.junit.After; + import org.junit.Assert; + import org.junit.Before; + import org.junit.FixMethodOrder; + import org.junit.Test; + import org.junit.runner.RunWith; + import org.junit.runners.MethodSorters; + import org.junit.runners.Parameterized; + import org.mockito.Mockito; + import org.onap.aai.AAISetup; + import org.onap.aai.db.props.AAIProperties; + import org.onap.aai.edges.enums.EdgeField; + import org.onap.aai.edges.enums.EdgeProperty; + import org.onap.aai.exceptions.AAIException; + import org.onap.aai.introspection.Introspector; + import org.onap.aai.introspection.Loader; + import org.onap.aai.introspection.ModelType; + import org.onap.aai.parsers.query.QueryParser; + import org.onap.aai.prevalidation.ValidationService; + import org.onap.aai.query.builder.Pageable; + import org.onap.aai.query.builder.QueryOptions; + import org.onap.aai.query.builder.Sort; + import org.onap.aai.query.builder.Sort.Direction; + import org.onap.aai.rest.db.responses.ErrorResponse; + import org.onap.aai.rest.db.responses.Relationship; + import org.onap.aai.rest.db.responses.RelationshipWrapper; + import org.onap.aai.rest.db.responses.ServiceException; + import org.onap.aai.rest.ueb.UEBNotification; + import org.onap.aai.restcore.HttpMethod; + import org.onap.aai.serialization.engines.QueryStyle; + import org.onap.aai.serialization.engines.TransactionalGraphEngine; + import org.onap.aai.util.AAIConfig; + import org.skyscreamer.jsonassert.JSONAssert; + import org.skyscreamer.jsonassert.JSONCompareMode; + import org.springframework.boot.test.mock.mockito.MockBean; + import org.springframework.http.HttpStatus; + + @RunWith(value = Parameterized.class) + @FixMethodOrder(MethodSorters.NAME_ASCENDING) + public class HttpEntryTest extends AAISetup { + + @MockBean ValidationService validationService; + + protected static final MediaType APPLICATION_JSON = MediaType.valueOf("application/json"); + + private static final Set<Integer> VALID_HTTP_STATUS_CODES = new HashSet<>(); + + static { + VALID_HTTP_STATUS_CODES.add(200); + VALID_HTTP_STATUS_CODES.add(201); + VALID_HTTP_STATUS_CODES.add(204); + } + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + /* + * TODO Change the HttpEntry instances accoringly + */ + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] { { QueryStyle.TRAVERSAL }, { QueryStyle.TRAVERSAL_URI } }); + } + + private Loader loader; + private TransactionalGraphEngine dbEngine; + private GraphTraversalSource traversal; + + private HttpHeaders httpHeaders; + + private UriInfo uriInfo; + + private MultivaluedMap<String, String> headersMultiMap; + private MultivaluedMap<String, String> queryParameters; + + private List<String> aaiRequestContextList; + + private List<MediaType> outputMediaTypes; + + ObjectMapper mapper = new ObjectMapper(); + + @Before + public void setup() { + + httpHeaders = Mockito.mock(HttpHeaders.class); + uriInfo = Mockito.mock(UriInfo.class); + + headersMultiMap = new MultivaluedHashMap<>(); + queryParameters = Mockito.spy(new MultivaluedHashMap<>()); + + headersMultiMap.add("X-FromAppId", "JUNIT"); + headersMultiMap.add("X-TransactionId", UUID.randomUUID().toString()); + headersMultiMap.add("Real-Time", "true"); + headersMultiMap.add("Accept", "application/json"); + headersMultiMap.add("aai-request-context", ""); + + outputMediaTypes = new ArrayList<>(); + outputMediaTypes.add(APPLICATION_JSON); + + aaiRequestContextList = new ArrayList<>(); + aaiRequestContextList.add(""); + + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); + loader = traversalHttpEntry.getLoader(); + dbEngine = traversalHttpEntry.getDbEngine(); + traversal = dbEngine.tx().traversal(); + + when(httpHeaders.getAcceptableMediaTypes()).thenReturn(outputMediaTypes); + when(httpHeaders.getRequestHeaders()).thenReturn(headersMultiMap); + + when(httpHeaders.getRequestHeader("aai-request-context")).thenReturn(aaiRequestContextList); + + when(uriInfo.getQueryParameters()).thenReturn(queryParameters); + when(uriInfo.getQueryParameters(false)).thenReturn(queryParameters); + + // TODO - Check if this is valid since RemoveDME2QueryParameters seems to be + // very unreasonable + Mockito.doReturn(null).when(queryParameters).remove(any()); + + when(httpHeaders.getMediaType()).thenReturn(APPLICATION_JSON); + } + + @After + public void rollback() { + dbEngine.rollback(); + } + + @Test + public void thatObjectCanBeRetrieved() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("equip-type", "theEquipType") + .property(AAIProperties.AAI_URI, uri) + .next(); + + JSONObject expectedResponseBody = new JSONObject() + .put("hostname", "theHostname") + .put("equip-type", "theEquipType"); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); + JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); + + JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); + assertEquals("Expected the pserver to be returned", 200, response.getStatus()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("equip-type", "theEquipType") + .property(AAIProperties.AAI_URI, uri) + .next(); + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname2") + .property("equip-type", "theEquipType2") + .property(AAIProperties.AAI_URI, uri + "2") + .next(); + + JSONObject expectedResponseBody = new JSONObject(); + JSONObject pserver1 = new JSONObject() + .put("hostname", "theHostname") + .put("equip-type", "theEquipType"); + JSONObject pserver2 = new JSONObject() + .put("hostname", "theHostname2") + .put("equip-type", "theEquipType2"); + expectedResponseBody.put("pserver", new JSONArray() + .put(pserver1) + .put(pserver2)); + + uri = "/cloud-infrastructure/pservers"; + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); + JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); + + JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); + assertEquals("Expected the pservers to be returned", 200, response.getStatus()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatPaginatedObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("equip-type", "theEquipType") + .property(AAIProperties.AAI_URI, uri) + .next(); + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname2") + .property("equip-type", "theEquipType2") + .property(AAIProperties.AAI_URI, uri + "2") + .next(); + + JSONObject expectedResponseBody = new JSONObject(); + JSONObject pserver1 = new JSONObject() + .put("hostname", "theHostname") + .put("equip-type", "theEquipType"); + expectedResponseBody.put("pserver", new JSONArray() + .put(pserver1)); + + uri = "/cloud-infrastructure/pservers"; + QueryOptions queryOptions = QueryOptions.builder().pageable(new Pageable(1, 1)).build(); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); + + assertNull(response.getHeaderString("total-results")); + assertEquals(1, actualResponseBody.getJSONArray("pserver").length()); + assertEquals("Expected the pservers to be returned", 200, response.getStatus()); + verify(validationService, times(1)).validate(any()); + + queryOptions = QueryOptions.builder().pageable(new Pageable(0,5).includeTotalCount()).build(); + response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + actualResponseBody = new JSONObject(response.getEntity().toString()); + assertEquals(2, actualResponseBody.getJSONArray("pserver").length()); + } + + @Test + public void thatPaginationWithNoResultsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + + uri = "/cloud-infrastructure/pservers"; + QueryOptions queryOptions = QueryOptions.builder().pageable(new Pageable(0, 1)).build(); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + + assertTrue(response.getEntity().toString().contains("Node Not Found:No Node of type pserver found at: /cloud-infrastructure/pservers")); + assertEquals(HttpStatus.NOT_FOUND.value(), response.getStatus()); + + queryOptions = QueryOptions.builder().pageable(new Pageable(0,1).includeTotalCount()).build(); + response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + + assertTrue( response.getEntity().toString().contains("Node Not Found:No Node of type pserver found at: /cloud-infrastructure/pservers")); + assertEquals(HttpStatus.NOT_FOUND.value(), response.getStatus()); + + } + + @Test + public void thatPagationResultWithTotalCountCanBeRetrieved() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("equip-type", "theEquipType") + .property(AAIProperties.AAI_URI, uri) + .next(); + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname2") + .property("equip-type", "theEquipType2") + .property(AAIProperties.AAI_URI, uri + "2") + .next(); + + JSONObject expectedResponseBody = new JSONObject(); + JSONObject pserver1 = new JSONObject() + .put("hostname", "theHostname") + .put("equip-type", "theEquipType"); + expectedResponseBody.put("pserver", new JSONArray() + .put(pserver1)); + + uri = "/cloud-infrastructure/pservers"; + QueryOptions queryOptions = QueryOptions.builder().pageable(new Pageable(1, 1).includeTotalCount()).build(); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); + String totalCount = response.getHeaderString("total-results"); + String totalPages = response.getHeaderString("total-pages"); + + assertEquals(2, Integer.parseInt(totalCount)); + assertEquals(2, Integer.parseInt(totalPages)); + assertEquals(1, actualResponseBody.getJSONArray("pserver").length()); + assertEquals("Expected the pservers to be returned", 200, response.getStatus()); + verify(validationService, times(1)).validate(any()); + + queryOptions = QueryOptions.builder().pageable(new Pageable(0, 2)).build(); + response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + actualResponseBody = new JSONObject(response.getEntity().toString()); + assertEquals(2, actualResponseBody.getJSONArray("pserver").length()); + } + + @Test + public void thatSortedObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("equip-type", "theEquipType") + .property(AAIProperties.AAI_URI, uri) + .next(); + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname2") + .property("equip-type", "theEquipType2") + .property(AAIProperties.AAI_URI, uri + "2") + .next(); + + JSONObject expectedResponseBody = new JSONObject(); + JSONObject pserver1 = new JSONObject() + .put("hostname", "theHostname") + .put("equip-type", "theEquipType"); + JSONObject pserver2 = new JSONObject() + .put("hostname", "theHostname2") + .put("equip-type", "theEquipType2"); + expectedResponseBody.put("pserver", new JSONArray() + .put(pserver1).put(pserver2)); + + // ascending + uri = "/cloud-infrastructure/pservers"; + QueryOptions queryOptions = QueryOptions.builder().sort(Sort.builder().property("equip-type").direction(Direction.ASC).build()).build(); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); + assertEquals("theEquipType", actualResponseBody.getJSONArray("pserver").getJSONObject(0).getString("equip-type")); + assertEquals("theEquipType2", actualResponseBody.getJSONArray("pserver").getJSONObject(1).getString("equip-type")); + + // descending + queryOptions = QueryOptions.builder().sort(Sort.builder().property("equip-type").direction(Direction.DESC).build()).build(); + response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, queryOptions); + actualResponseBody = new JSONObject(response.getEntity().toString()); + assertEquals("theEquipType2", actualResponseBody.getJSONArray("pserver").getJSONObject(0).getString("equip-type")); + assertEquals("theEquipType", actualResponseBody.getJSONArray("pserver").getJSONObject(1).getString("equip-type")); + + } + + @Test + public void thatObjectsCanNotBeFound() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/junit-test2"; + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); + assertEquals("The pserver is not found", 404, response.getStatus()); + } + + @Test + public void thatObjectCanBeCreatedViaPUT() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + String requestBody = new JSONObject().put("hostname", "theHostname").toString(); + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatObjectCreationFailsWhenResourceVersionIsProvided() + throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + String requestBody = new JSONObject() + .put("hostname", "theHostname") + .put("resource-version", "123") + .toString(); + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); + ErrorResponse errorResponseEntity = mapper.readValue(response.getEntity().toString(), ErrorResponse.class); + assertEquals("Expecting the pserver to be created", 412, response.getStatus()); + assertEquals( + "Resource version specified on create:resource-version passed for create of /cloud-infrastructure/pservers/pserver/theHostname", + errorResponseEntity.getRequestError().getServiceException().getVariables().get(2)); + } + + @Test + public void thatObjectCanBeUpdatedViaPUT() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("number-of-cpus", "10") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .next(); + String requestBody = new JSONObject() + .put("hostname", "updatedHostname") + .put("resource-version", "123") + .toString(); + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); + assertEquals("Expecting the pserver to be updated", 200, response.getStatus()); + assertTrue("That old properties are removed", + traversal.V().has("hostname", "updatedHostname").hasNot("number-of-cpus").hasNext()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatUpdateFailsWhenResourceVersionsMismatch() + throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .next(); + String requestBody = new JSONObject() + .put("hostname", "updatedHostname") + .put("resource-version", "456") + .toString(); + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); + ErrorResponse errorResponseEntity = mapper.readValue(response.getEntity().toString(), ErrorResponse.class); + assertEquals("Expecting the update to fail", 412, response.getStatus()); + assertEquals( + "Precondition Failed:resource-version MISMATCH for update of /cloud-infrastructure/pservers/pserver/updatedHostname", + errorResponseEntity.getRequestError().getServiceException().getVariables().get(2)); + } + + @Test + public void thatUpdateFailsWhenResourceVersionIsNotProvided() + throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("in-maint", "false") + .property(AAIProperties.AAI_URI, uri) + .next(); + + String requestBody = new JSONObject() + .put("hostname", "theHostname") + .put("is-maint", "true") + .toString(); + + doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); + ErrorResponse errorResponseEntity = mapper.readValue(response.getEntity().toString(), ErrorResponse.class); + assertEquals("Request should fail when no resource-version is provided", 412, response.getStatus()); + assertEquals( + "Precondition Required:resource-version not passed for update of /cloud-infrastructure/pservers/pserver/theHostname", + errorResponseEntity.getRequestError().getServiceException().getVariables().get(2)); + } + + @Test + public void thatCreateViaPUTAddsRelationshipsToExistingObjects() throws UnsupportedEncodingException, AAIException { + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "hostname") + .property(AAIProperties.AAI_URI, "/cloud-infrastructure/pservers/pserver/hostname") + .next(); + String uri = "/cloud-infrastructure/pservers/pserver/hostname/p-interfaces/p-interface/p1"; + String requestBody = new JSONObject().put("interface-name", "p1").toString(); + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, requestBody); + assertEquals("response is successful", 201, response.getStatus()); + assertTrue("p-interface was created", + traversal.V().has("aai-node-type", "p-interface").has("interface-name", "p1").hasNext()); + assertTrue("p-interface has outgoing edge to p-server", + traversal.V().has("aai-node-type", "p-interface").has("aai-uri", uri).has("interface-name", "p1") + .out("tosca.relationships.network.BindsTo").has("aai-node-type", "pserver") + .has("hostname", "hostname").hasNext()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatObjectsCanBePatched() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/the-hostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "the-hostname") + .property("equip-type", "the-equip-type") + .property(AAIProperties.AAI_URI, uri) + .next(); + String requestBody = new JSONObject() + .put("hostname", "new-hostname") + .toString(); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.MERGE_PATCH, uri, requestBody); + assertEquals("Expected the pserver to be updated", 200, response.getStatus()); + assertTrue("object should be updated while keeping old properties", + traversal.V().has("aai-node-type", "pserver").has("hostname", "new-hostname") + .has("equip-type", "the-equip-type").hasNext()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatObjectsCanBeDeleted() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/the-hostname"; + String resourceVersion = "123"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "the-hostname") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, resourceVersion) + .next(); + assertEquals("Expecting a No Content response", 204, + doDelete(resourceVersion, uri, "pserver").getStatus()); + assertTrue("Expecting the pserver to be deleted", + !traversal.V().has("aai-node-type", "pserver").has("hostname", "the-hostname").hasNext()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatRelationshipCanBeCreated() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/edge-test-pserver"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "edge-test-pserver") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .next(); + uri = "/cloud-infrastructure/complexes/complex/edge-test-complex"; + traversal.addV() + .property("aai-node-type", "complex") + .property("physical-location-id", "edge-test-complex") + .property("physical-location-type", "AAIDefault") + .property("street1", "AAIDefault") + .property("city", "AAIDefault") + .property("postal-code", "07748") + .property("country", "USA") + .property("region", "US") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "234") + .next(); + + uri = "/cloud-infrastructure/complexes/complex/edge-test-complex/relationship-list/relationship"; + String requestBody = new JSONObject() + .put("related-to", "pserver") + .put("related-link", + String.format("/aai/%s/cloud-infrastructure/pservers/pserver/edge-test-pserver", + schemaVersions.getDefaultVersion().toString())) + .put("relationship-label", "org.onap.relationships.inventory.LocatedIn") + .toString(); + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, requestBody); + assertEquals("Expected the pserver relationship to be created", 200, response.getStatus()); + GraphTraversal<Vertex, Vertex> vertexQuery = traversal.V() + .has("aai-node-type", "complex") + .has("physical-location-id", "edge-test-complex") + .in("org.onap.relationships.inventory.LocatedIn") + .has("aai-node-type", "pserver") + .has("hostname", "edge-test-pserver"); + GraphTraversal<Edge, Edge> edgeQuery = traversal.E() + .has(EdgeField.PRIVATE.toString(), "false") + .has(EdgeProperty.CONTAINS.toString(), NONE.toString()) + .has(EdgeProperty.DELETE_OTHER_V.toString(), NONE.toString()) + .has(EdgeProperty.PREVENT_DELETE.toString(), "IN"); + assertTrue("p-server has incoming edge from complex", vertexQuery.hasNext()); + assertTrue("Created Edge has expected properties", edgeQuery.hasNext()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatRelationshipCanNotBeCreatedEdgeMultiplicity() + throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { + String uri = "/cloud-infrastructure/pservers/pserver/httpEntryTest-pserver-01"; + traversal + .addV() // pserver + .property("aai-node-type", "pserver") + .property("hostname", "httpEntryTest-pserver-01") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .as("v1") + .addV() // complex + .property("aai-node-type", "complex") + .property("physical-location-id", "httpEntryTest-complex-01") + .property("physical-location-type", "AAIDefault") + .property("street1", "AAIDefault") + .property("city", "AAIDefault") + .property("postal-code", "07748") + .property("country", "USA") + .property("region", "US") + .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/httpEntryTest-complex-01") + .property(AAIProperties.RESOURCE_VERSION, "234") + .as("v2") + // edge between pserver and complex + .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") + .next(); + + // Put Relationship + uri = "/cloud-infrastructure/pservers/pserver/httpEntryTest-pserver-01/relationship-list/relationship"; + String requestBody = new JSONObject() + .put("related-to", "complex") + .put("related-link", + String.format("/aai/%s/cloud-infrastructure/complexes/complex/httpEntryTest-complex-01", + schemaVersions.getDefaultVersion().toString())) + .put("relationship-label", "org.onap.relationships.inventory.LocatedIn") + .toString(); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, requestBody); + ServiceException serviceException = mapper.readValue(response.getEntity().toString(), ErrorResponse.class) + .getRequestError().getServiceException(); + + assertEquals("Expected the response code to be Bad Request", 400, response.getStatus()); + assertEquals("ERR.5.4.6140", serviceException.getVariables().get(3)); + assertEquals( + "Edge multiplicity violated:multiplicity rule violated: only one edge can exist with label: org.onap.relationships.inventory.LocatedIn between pserver and complex", + serviceException.getVariables().get(2)); + } + + @Test + public void putEdgeWrongLabelTest() + throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { + String uri = "/cloud-infrastructure/pservers/pserver/edge-test-pserver"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "edge-test-pserver") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .next(); + uri = "/cloud-infrastructure/complexes/complex/edge-test-complex"; + traversal.addV() + .property("aai-node-type", "complex") + .property("physical-location-id", "edge-test-complex") + .property("physical-location-type", "AAIDefault") + .property("street1", "AAIDefault") + .property("city", "AAIDefault") + .property("postal-code", "07748") + .property("country", "USA") + .property("region", "US") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "234") + .next(); + + uri = "/cloud-infrastructure/complexes/complex/edge-test-complex/relationship-list/relationship"; + String requestBody = new JSONObject() + .put("related-to", "pserver") + .put("related-link", + String.format("/aai/%s/cloud-infrastructure/pservers/pserver/edge-test-pserver", + schemaVersions.getDefaultVersion().toString())) + .put("relationship-label", "does.not.exist") + .toString(); + + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, requestBody); + ServiceException serviceException = mapper.readValue(response.getEntity().toString(), ErrorResponse.class) + .getRequestError().getServiceException(); + + assertEquals("Expected the pserver to be created", 400, response.getStatus()); + assertEquals("ERR.5.4.6107", serviceException.getVariables().get(3)); + assertEquals( + "Required Edge-property not found in input data:org.onap.aai.edges.exceptions.EdgeRuleNotFoundException: No rule found for EdgeRuleQuery with filter params node type: complex, node type: pserver, label: does.not.exist, type: COUSIN, isPrivate: false.", + serviceException.getVariables().get(2)); + } + + @Test + public void thatObjectsCanBeRetrievedInPathedResponseFormat() throws UnsupportedEncodingException, AAIException { + traversal + .addV() // pserver + .property("aai-node-type", "pserver") + .property("hostname", "pserver-1") + .property(AAIProperties.AAI_URI, "/cloud-infrastructure/pservers/pserver/pserver-1") + .property(AAIProperties.RESOURCE_VERSION, "123") + .addV() // pserver + .property("aai-node-type", "pserver") + .property("hostname", "pserver-2") + .property(AAIProperties.AAI_URI, "/cloud-infrastructure/pservers/pserver/pserver-2") + .property(AAIProperties.RESOURCE_VERSION, "234") + .next(); + + queryParameters.add("format", "pathed"); + String requestBody = ""; + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, + "/cloud-infrastructure/pservers"); + queryParameters.remove("format"); + + String responseEntity = response.getEntity().toString(); + assertEquals("Expected get to succeed", 200, response.getStatus()); + assertThat(responseEntity, containsString("/cloud-infrastructure/pservers/pserver/pserver-1")); + assertThat(responseEntity, containsString("/cloud-infrastructure/pservers/pserver/pserver-2")); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void thatRelatedObjectsCanBeRetrieved() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; + traversal + .addV() // pserver + .property("aai-node-type", "pserver") + .property("hostname", "related-to-pserver") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .as("v1") + .addV() // complex + .property("aai-node-type", "complex") + .property("physical-location-id", "related-to-complex") + .property("physical-location-type", "AAIDefault") + .property("street1", "AAIDefault") + .property("city", "AAIDefault") + .property("postal-code", "07748") + .property("country", "USA") + .property("region", "US") + .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/related-to-complex") + .property(AAIProperties.RESOURCE_VERSION, "234") + .as("v2") + // edge between pserver and complex + .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") + .next(); + + uri = "/cloud-infrastructure/complexes/complex/related-to-complex/related-to/pservers"; + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); + + assertEquals("Expected the response to be successful", 200, response.getStatus()); + assertThat("Related pserver is returned", response.getEntity().toString(), + containsString("\"hostname\":\"related-to-pserver\"")); + verify(validationService, times(1)).validate(any()); + + } + + @Test + public void getAbstractTest() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/abstract-pserver"; + traversal + .addV() // pserver + .property("aai-node-type", "pserver") + .property("hostname", "abstract-pserver") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .as("v1") + .addV() // generic-vnf + .property("aai-node-type", "generic-vnf") + .property("vnf-id", "abstract-generic-vnf") + .property("vnf-name", "the-vnf-name") + .property(AAIProperties.AAI_URI, "/network/generic-vnfs/generic-vnf/abstract-generic-vnf") + .property(AAIProperties.RESOURCE_VERSION, "234") + .as("v2") + // edge between pserver and generic-vnf + .addE("tosca.relationships.HostedOn").from("v2").to("v1") + .next(); + + uri = "/network/generic-vnfs/generic-vnf/abstract-generic-vnf/related-to/pservers"; + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); + assertThat("Related to pserver is returned.", response.getEntity().toString(), + containsString("\"hostname\":\"abstract-pserver\"")); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void getRelationshipListTest() + throws UnsupportedEncodingException, AAIException, JsonMappingException, JsonProcessingException { + String uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; + traversal + .addV() // pserver + .property("aai-node-type", "pserver") + .property("hostname", "related-to-pserver") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .as("v1") + .addV() // complex + .property("aai-node-type", "complex") + .property("physical-location-id", "related-to-complex") + .property("physical-location-type", "AAIDefault") + .property("street1", "AAIDefault") + .property("city", "AAIDefault") + .property("postal-code", "07748") + .property("country", "USA") + .property("region", "US") + .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/related-to-complex") + .property(AAIProperties.RESOURCE_VERSION, "234") + .as("v2") + // edge between pserver and complex + .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") + // these properties are required when finding related edges + .property(EdgeProperty.CONTAINS.toString(), NONE.toString()) + .property(EdgeField.PRIVATE.toString(), "false") + .next(); + + // Get Relationship + uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET_RELATIONSHIP, uri); + Relationship[] relationships = mapper.readValue(response.getEntity().toString(), RelationshipWrapper.class) + .getRelationships(); + + assertEquals("complex", relationships[0].getRelatedTo()); + assertEquals("org.onap.relationships.inventory.LocatedIn", relationships[0].getRelationshipLabel()); + assertEquals("/aai/v14/cloud-infrastructure/complexes/complex/related-to-complex", + relationships[0].getRelatedLink()); + assertEquals("complex.physical-location-id", relationships[0].getRelationshipData()[0].getRelationshipKey()); + assertEquals("related-to-complex", relationships[0].getRelationshipData()[0].getRelationshipValue()); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void getRelationshipListTestWithFormatSimple() throws UnsupportedEncodingException, AAIException { + String uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; + traversal + .addV() // pserver + .property("aai-node-type", "pserver") + .property("hostname", "related-to-pserver") + .property(AAIProperties.AAI_URI, uri) + .property(AAIProperties.RESOURCE_VERSION, "123") + .as("v1") + .addV() // complex + .property("aai-node-type", "complex") + .property("physical-location-id", "related-to-complex") + .property("physical-location-type", "AAIDefault") + .property("street1", "AAIDefault") + .property("city", "AAIDefault") + .property("postal-code", "07748") + .property("country", "USA") + .property("region", "US") + .property(AAIProperties.AAI_URI, "/cloud-infrastructure/complexes/complex/related-to-complex") + .property(AAIProperties.RESOURCE_VERSION, "234") + .as("v2") + // edge between pserver and complex + .addE("org.onap.relationships.inventory.LocatedIn").from("v1").to("v2") + // these properties are required when finding related edges + .property(EdgeProperty.CONTAINS.toString(), NONE.toString()) + .property(EdgeField.PRIVATE.toString(), "false") + .next(); + + // Get Relationship + uri = "/cloud-infrastructure/pservers/pserver/related-to-pserver"; + queryParameters.add("format", "resource"); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET_RELATIONSHIP, uri); + + JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); + + // Define the expected response + JSONObject relationshipData = new JSONObject().put("relationship-key", "complex.physical-location-id") + .put("relationship-value", "related-to-complex"); + JSONObject relationship = new JSONObject() + .put("related-to", "complex") + .put("relationship-label", "org.onap.relationships.inventory.LocatedIn") + .put("related-link", + String.format("/aai/%s/cloud-infrastructure/complexes/complex/related-to-complex", + schemaVersions.getDefaultVersion())) + .put("relationship-data", new JSONArray().put(relationshipData)); + JSONObject pserver = new JSONObject() + .put("hostname", "related-to-pserver") + .put("resource-version", "123") + .put("relationship-list", new JSONObject().put("relationship", new JSONArray().put(relationship))); + JSONObject expectedResponseBody = new JSONObject() + .put("results", new JSONArray().put(new JSONObject().put("pserver", pserver))); + + JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); + queryParameters.remove("format"); + verify(validationService, times(1)).validate(any()); + } + + @Test + public void notificationOnRelatedToTest() throws UnsupportedEncodingException, AAIException { + + Loader ld = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); + UEBNotification uebNotification = Mockito.spy(new UEBNotification(ld, loaderFactory, schemaVersions)); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), uebNotification); + + Loader loader = traversalHttpEntry.getLoader(); + TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); + // Put pserver + String uri = "/cloud-infrastructure/pservers/pserver/junit-edge-test-pserver"; + String content = "{\"hostname\":\"junit-edge-test-pserver\"}"; + doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, content); + // Put complex + uri = "/cloud-infrastructure/complexes/complex/junit-edge-test-complex"; + content = "{\"physical-location-id\":\"junit-edge-test-complex\",\"physical-location-type\":\"AAIDefault\",\"street1\":\"AAIDefault\",\"city\":\"AAIDefault\",\"state\":\"NJ\",\"postal-code\":\"07748\",\"country\":\"USA\",\"region\":\"US\"}"; + doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT, uri, content); + + // PutEdge + uri = "/cloud-infrastructure/complexes/complex/junit-edge-test-complex/relationship-list/relationship"; + content = "{\"related-to\":\"pserver\",\"related-link\":\"/aai/" + schemaVersions.getDefaultVersion().toString() + + "/cloud-infrastructure/pservers/pserver/junit-edge-test-pserver\",\"relationship-label\":\"org.onap.relationships.inventory.LocatedIn\"}"; + + doNothing().when(uebNotification).triggerEvents(); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, content); + + assertEquals("Expected the pserver relationship to be deleted", 200, response.getStatus()); + assertEquals("Two notifications", 2, uebNotification.getEvents().size()); + assertEquals("Notification generated for PUT edge", "UPDATE", + uebNotification.getEvents().get(0).getEventHeader().getValue("action").toString()); + assertThat("Event body for the edge create has the related to", + uebNotification.getEvents().get(0).getObj().marshal(false), + containsString("cloud-infrastructure/pservers/pserver/junit-edge-test-pserver")); + + response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.DELETE_EDGE, uri, content); + assertEquals("Expected the pserver relationship to be deleted", 204, response.getStatus()); + assertEquals("Two notifications", 2, uebNotification.getEvents().size()); + assertEquals("Notification generated for DELETE edge", "UPDATE", + uebNotification.getEvents().get(0).getEventHeader().getValue("action").toString()); + assertThat("Event body for the edge delete does not have the related to", + uebNotification.getEvents().get(0).getObj().marshal(false), + not(containsString("cloud-infrastructure/pservers/pserver/junit-edge-test-pserver"))); + dbEngine.rollback(); + + } + + private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, + String uri) throws UnsupportedEncodingException, AAIException { + return doRequest(httpEntry, loader, dbEngine, method, uri, null, null); + } + + private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, + String uri, String requestBody) throws UnsupportedEncodingException, AAIException { + return doRequest(httpEntry, loader, dbEngine, method, uri, requestBody, null); + } + private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, + String uri, QueryOptions queryOptions) throws UnsupportedEncodingException, AAIException { + return doRequest(httpEntry, loader, dbEngine, method, uri, null, queryOptions); + } + + private Response doRequest(HttpEntry httpEntry, Loader loader, TransactionalGraphEngine dbEngine, HttpMethod method, + String uri, String requestBody, QueryOptions queryOptions) throws UnsupportedEncodingException, AAIException { + URI uriObject = UriBuilder.fromPath(uri).build(); + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + String objType; + if (!uriQuery.getContainerType().equals("")) { + objType = uriQuery.getContainerType(); + } else { + objType = uriQuery.getResultType(); + } + if (uri.endsWith("relationship")) { + objType = "relationship"; + } + Introspector obj; + if (method.equals(HttpMethod.GET) || method.equals(HttpMethod.GET_RELATIONSHIP)) { + obj = loader.introspectorFromName(objType); + } else { + obj = loader.unmarshal(objType, requestBody, org.onap.aai.restcore.MediaType.getEnum("application/json")); + } + + DBRequest.Builder builder = new DBRequest.Builder(method, uriObject, uriQuery, obj, httpHeaders, uriInfo, + "JUNIT-TRANSACTION"); + DBRequest dbRequest = requestBody != null + ? builder.rawRequestContent(requestBody).build() + : builder.build(); + + List<DBRequest> dbRequestList = Collections.singletonList(dbRequest); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = httpEntry.process(dbRequestList, "JUNIT", Collections.emptySet(), true, queryOptions); + return responsesTuple.getValue1().get(0).getValue1(); + } + + private Response doDelete(String resourceVersion, String uri, String nodeType) + throws UnsupportedEncodingException, AAIException { + queryParameters.add("resource-version", resourceVersion); + + URI uriObject = UriBuilder.fromPath(uri).build(); + + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + String content = ""; + + Introspector obj = loader.introspectorFromName(nodeType); + + DBRequest dbRequest = new DBRequest.Builder(HttpMethod.DELETE, uriObject, uriQuery, obj, httpHeaders, uriInfo, + "JUNIT-TRANSACTION").rawRequestContent(content).build(); + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = traversalHttpEntry.process(Arrays.asList(dbRequest), + "JUNIT"); + return responsesTuple.getValue1().get(0).getValue1(); + } + + @Test + public void setDepthTest() throws AAIException { + System.setProperty("AJSC_HOME", "."); + System.setProperty("BUNDLECONFIG_DIR", "src/main/test/resources"); + + String depthParam = AAIConfig.get("aai.rest.getall.depthparam"); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); + int depth = traversalHttpEntry.setDepth(null, depthParam); + assertEquals(AAIProperties.MAXIMUM_DEPTH.intValue(), depth); + } + + @Test + public void thatEventsAreValidated() throws AAIException, UnsupportedEncodingException { + String uri = "/cloud-infrastructure/pservers/pserver/theHostname"; + traversal.addV() + .property("aai-node-type", "pserver") + .property("hostname", "theHostname") + .property("equip-type", "theEquipType") + .property(AAIProperties.AAI_URI, uri) + .next(); + + JSONObject expectedResponseBody = new JSONObject() + .put("hostname", "theHostname") + .put("equip-type", "theEquipType"); + Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri); + JSONObject actualResponseBody = new JSONObject(response.getEntity().toString()); + + JSONAssert.assertEquals(expectedResponseBody, actualResponseBody, JSONCompareMode.NON_EXTENSIBLE); + assertEquals("Expected the pserver to be returned", 200, response.getStatus()); + verify(validationService, times(1)).validate(any()); + } + } diff --git a/aai-els-onap-logging/pom.xml b/aai-els-onap-logging/pom.xml index e1b27a11..fa158035 100644 --- a/aai-els-onap-logging/pom.xml +++ b/aai-els-onap-logging/pom.xml @@ -4,7 +4,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-els-onap-logging</artifactId> diff --git a/aai-failover/pom.xml b/aai-failover/pom.xml index 2127e27b..f892b117 100644 --- a/aai-failover/pom.xml +++ b/aai-failover/pom.xml @@ -5,7 +5,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <modelVersion>4.0.0</modelVersion> diff --git a/aai-parent/pom.xml b/aai-parent/pom.xml index e86f1012..fa9c08bc 100644 --- a/aai-parent/pom.xml +++ b/aai-parent/pom.xml @@ -27,7 +27,7 @@ limitations under the License. <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-common</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> </parent> <artifactId>aai-parent</artifactId> <name>aai-parent</name> diff --git a/aai-rest/pom.xml b/aai-rest/pom.xml index f4ed8dbd..298783d3 100644 --- a/aai-rest/pom.xml +++ b/aai-rest/pom.xml @@ -29,7 +29,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-rest</artifactId> diff --git a/aai-schema-abstraction/pom.xml b/aai-schema-abstraction/pom.xml index 0a46974f..52db4c3b 100644 --- a/aai-schema-abstraction/pom.xml +++ b/aai-schema-abstraction/pom.xml @@ -28,7 +28,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> diff --git a/aai-schema-ingest/pom.xml b/aai-schema-ingest/pom.xml index 817e9f51..326082da 100644 --- a/aai-schema-ingest/pom.xml +++ b/aai-schema-ingest/pom.xml @@ -26,7 +26,7 @@ limitations under the License. <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-schema-ingest</artifactId> diff --git a/aai-utils/pom.xml b/aai-utils/pom.xml index 40b05888..56d14a26 100644 --- a/aai-utils/pom.xml +++ b/aai-utils/pom.xml @@ -27,7 +27,7 @@ <parent> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-parent</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> <artifactId>aai-utils</artifactId> @@ -30,7 +30,7 @@ <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-common</artifactId> - <version>1.14.3-SNAPSHOT</version> + <version>1.14.4-SNAPSHOT</version> <packaging>pom</packaging> <name>aai-aai-common</name> <description>Contains all of the common code for resources and traversal repos</description> diff --git a/version.properties b/version.properties index a9c3f226..82f9610a 100644 --- a/version.properties +++ b/version.properties @@ -5,7 +5,7 @@ major_version=1 minor_version=14 -patch_version=3 +patch_version=4 base_version=${major_version}.${minor_version}.${patch_version} |