summaryrefslogtreecommitdiffstats
path: root/aai-core/src/main/java/org/onap/aai/serialization
diff options
context:
space:
mode:
authorVenkata Harish K Kajur <vk250x@att.com>2017-09-28 12:43:08 -0400
committerVenkata Harish K Kajur <vk250x@att.com>2017-09-28 13:29:27 -0400
commit1767960099ea2983eef5218b8ce44b167ae0774c (patch)
tree4efe13601c1f9ebebc6026b32ec749778cd96caf /aai-core/src/main/java/org/onap/aai/serialization
parenta8a05641920545aa094dffdb016b7b5febe9a879 (diff)
Change openecomp to onap and update license
Issue-ID: AAI-61 AAI-82 Change-Id: Iae98d4bf4c693c0a3203158bff98c3c5e739f453 Signed-off-by: Venkata Harish K Kajur <vk250x@att.com>
Diffstat (limited to 'aai-core/src/main/java/org/onap/aai/serialization')
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/AAIDirection.java35
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java1444
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/DeleteSemantic.java41
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperties.java44
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperty.java45
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/EdgePropertyMap.java60
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRule.java211
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java589
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/EdgeType.java27
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/GetAllPool.java47
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java70
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/LegacyDBSerializer.java35
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/MultiplicityRule.java29
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/TitanGraphSingleton.java39
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/EdgeMultiplicityException.java41
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java41
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java26
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/TitanDBEngine.java102
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java246
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java198
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinPipelineQueryEngine.java206
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinQueryEngine.java196
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java94
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java43
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java31
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java97
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java32
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java80
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java63
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java71
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java70
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java190
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java163
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/SimpleFormat.java76
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/SubGraphStyle.java28
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java41
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/QueryParamInjectionException.java41
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Depth.java29
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Inject.java35
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/NodesOnly.java29
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Setter.java37
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java85
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/UrlBuilder.java92
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedEdge.java81
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedVertex.java163
45 files changed, 5443 insertions, 0 deletions
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/AAIDirection.java b/aai-core/src/main/java/org/onap/aai/serialization/db/AAIDirection.java
new file mode 100644
index 00000000..1dce588d
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/AAIDirection.java
@@ -0,0 +1,35 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+public enum AAIDirection {
+ IN, OUT, BOTH, NONE;
+
+ public AAIDirection opposite() {
+ if (this.equals(OUT))
+ return IN;
+ else if (this.equals(IN))
+ return OUT;
+ else
+ return BOTH;
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java b/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java
new file mode 100644
index 00000000..dd073dc7
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java
@@ -0,0 +1,1444 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.base.CaseFormat;
+import com.thinkaurelius.titan.core.SchemaViolationException;
+import org.apache.commons.collections.IteratorUtils;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.*;
+import org.javatuples.Pair;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.*;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.introspection.sideeffect.DataCopy;
+import org.onap.aai.introspection.sideeffect.DataLinkReader;
+import org.onap.aai.introspection.sideeffect.DataLinkWriter;
+import org.onap.aai.introspection.sideeffect.SideEffectRunner;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.parsers.query.QueryParser;
+import org.onap.aai.parsers.uri.URIParser;
+import org.onap.aai.parsers.uri.URIToRelationshipObject;
+import org.onap.aai.query.builder.QueryBuilder;
+import org.onap.aai.schema.enums.ObjectMetadata;
+import org.onap.aai.schema.enums.PropertyMetadata;
+import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.serialization.tinkerpop.TreeBackedVertex;
+import org.onap.aai.util.AAIApiServerURLBase;
+import org.onap.aai.util.AAIConfig;
+import org.onap.aai.util.AAIConstants;
+import org.onap.aai.workarounds.NamingExceptions;
+
+import javax.ws.rs.core.UriBuilder;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+public class DBSerializer {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
+
+ private final TransactionalGraphEngine engine;
+ private final String sourceOfTruth;
+ private final ModelType introspectionType;
+ private final Version version;
+ private final Loader latestLoader;
+ private final EdgeRules edgeRules = EdgeRules.getInstance();
+ private final Loader loader;
+ private final String baseURL;
+ /**
+ * Instantiates a new DB serializer.
+ *
+ * @param version the version
+ * @param engine the engine
+ * @param g the g
+ * @param introspectionType the introspection type
+ * @param sourceOfTruth the source of truth
+ * @param llBuilder the ll builder
+ * @throws AAIException
+ */
+ public DBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
+ this.engine = engine;
+ this.sourceOfTruth = sourceOfTruth;
+ this.introspectionType = introspectionType;
+ this.latestLoader = LoaderFactory.createLoaderForVersion(introspectionType, AAIProperties.LATEST);
+ this.version = version;
+ this.loader = LoaderFactory.createLoaderForVersion(introspectionType, version);
+ this.baseURL = AAIApiServerURLBase.get(version);
+ }
+
+ /**
+ * Touch standard vertex properties.
+ *
+ * @param v the v
+ * @param isNewVertex the is new vertex
+ */
+ public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
+
+ long unixTimeNow = System.currentTimeMillis();
+ String timeNowInSec = "" + unixTimeNow;
+ if (isNewVertex) {
+ v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
+ v.property(AAIProperties.CREATED_TS, timeNowInSec);
+ }
+ v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec );
+ v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
+ v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
+
+ }
+
+ private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) {
+
+ v.property(AAIProperties.NODE_TYPE, nodeType);
+ touchStandardVertexProperties(v, isNewVertex);
+
+ }
+
+
+
+ /**
+ * Creates the new vertex.
+ *
+ * @param wrappedObject the wrapped object
+ * @return the vertex
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public Vertex createNewVertex(Introspector wrappedObject) {
+
+
+ Vertex v = this.engine.tx().addVertex();
+ touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
+
+ return v;
+ }
+
+ /**
+ * Trim class name.
+ *
+ * @param className the class name
+ * @return the string
+ */
+ /*
+ * Removes the classpath from a class name
+ */
+ public String trimClassName (String className) {
+ String returnValue = "";
+
+ if (className.lastIndexOf('.') == -1) {
+ return className;
+ }
+ returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
+
+ return returnValue;
+ }
+
+ /**
+ * Serialize to db.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @param uriQuery the uri query
+ * @param identifier the identifier
+ * @throws SecurityException the security exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws InterruptedException the interrupted exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ try {
+ if (uriQuery.isDependent()) {
+ //try to find the parent
+ List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
+ if (!vertices.isEmpty()) {
+ Vertex parent = vertices.get(0);
+ this.reflectDependentVertex(parent, v, obj, requestContext);
+ } else {
+ throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
+ }
+ } else {
+ serializeSingleVertex(v, obj, requestContext);
+ }
+
+ } catch (SchemaViolationException e) {
+ throw new AAIException("AAI_6117", e);
+ }
+
+ }
+
+ public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
+ try {
+ boolean isTopLevel = obj.isTopLevel();
+ if (isTopLevel) {
+ v.property(AAIProperties.AAI_URI, obj.getURI());
+ }
+ processObject(obj, v, requestContext);
+ if (!isTopLevel) {
+ URI uri = this.getURIForVertex(v);
+ URIParser parser = new URIParser(this.loader, uri);
+ if (parser.validate()) {
+ VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
+ if (!uriProp.isPresent() || uriProp.isPresent() && !uriProp.value().equals(uri.toString())) {
+ v.property(AAIProperties.AAI_URI, uri.toString());
+ }
+ }
+ }
+ } catch (SchemaViolationException e) {
+ throw new AAIException("AAI_6117", e);
+ }
+ }
+
+ /**
+ * Process object.
+ *
+ * @param <T> the generic type
+ * @param obj the obj
+ * @param v the v
+ * @return the list
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ /*
+ * Helper method for reflectToDb
+ * Handles all the property setting
+ */
+ private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
+ Set<String> properties = new LinkedHashSet<>(obj.getProperties());
+ properties.remove(AAIProperties.RESOURCE_VERSION);
+ List<Vertex> dependentVertexes = new ArrayList<>();
+ List<Vertex> processedVertexes = new ArrayList<>();
+ boolean isComplexType = false;
+ boolean isListType = false;
+ if (!obj.isContainer()) {
+ this.touchStandardVertexProperties(obj.getDbName(), v, false);
+ }
+ this.executePreSideEffects(obj, v);
+ for (String property : properties) {
+ Object value = null;
+ final String propertyType;
+ propertyType = obj.getType(property);
+ isComplexType = obj.isComplexType(property);
+ isListType = obj.isListType(property);
+ value = obj.getValue(property);
+
+ if (!(isComplexType || isListType)) {
+ boolean canModify = this.canModify(obj, property, requestContext);
+
+ if (canModify) {
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
+ String dbProperty = property;
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+ if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
+ //data linked properties are ephemeral
+ //they are populated dynamically on GETs
+ continue;
+ }
+ if (value != null) {
+ if (!value.equals(v.property(dbProperty).orElse(null))) {
+ if (propertyType.toLowerCase().contains(".long")) {
+ v.property(dbProperty, new Integer(((Long)value).toString()));
+ } else {
+ v.property(dbProperty, value);
+ }
+ }
+ } else {
+ v.property(dbProperty).remove();
+ }
+ }
+ } else if (isListType) {
+ List<Object> list = (List<Object>)value;
+ if (obj.isComplexGenericType(property)) {
+ if (list != null) {
+ for (Object o : list) {
+ Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
+ child.setURIChain(obj.getURI());
+ processedVertexes.add(reflectDependentVertex(v, child, requestContext));
+ }
+ }
+ } else {
+ //simple list case
+ engine.setListProperty(v, property, list);
+ }
+ } else {
+ //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
+ if (value != null) { //effectively ignore complex properties not included in the object we're processing
+ if (value.getClass().isArray()) {
+
+ int length = Array.getLength(value);
+ for (int i = 0; i < length; i ++) {
+ Object arrayElement = Array.get(value, i);
+ Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
+ child.setURIChain(obj.getURI());
+ processedVertexes.add(reflectDependentVertex(v, child, requestContext));
+
+ }
+ } else if (!property.equals("relationship-list")) {
+ // container case
+ Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
+ if (introspector.isContainer()) {
+ dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
+ introspector.setURIChain(obj.getURI());
+
+ processedVertexes.addAll(processObject(introspector, v, requestContext));
+
+ } else {
+ dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
+ processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
+
+ }
+ } else if (property.equals("relationship-list")) {
+ handleRelationships(obj, v);
+ }
+ }
+ }
+ }
+ this.writeThroughDefaults(v, obj);
+ /* handle those vertexes not touched */
+ for (Vertex toBeRemoved : processedVertexes) {
+ dependentVertexes.remove(toBeRemoved);
+ }
+ this.deleteItemsWithTraversal(dependentVertexes);
+
+ this.executePostSideEffects(obj, v);
+ return processedVertexes;
+ }
+
+ /**
+ * Handle relationships.
+ *
+ * @param obj the obj
+ * @param vertex the vertex
+ * @throws SecurityException the security exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ /*
+ * Handles the explicit relationships defined for an obj
+ */
+ private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
+
+
+
+ Introspector wrappedRl = obj.getWrappedValue("relationship-list");
+ processRelationshipList(wrappedRl, vertex);
+
+
+ }
+
+
+ /**
+ * Process relationship list.
+ *
+ * @param wrapped the wrapped
+ * @param v the v
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
+
+ List<Object> relationships = (List<Object>)wrapped.getValue("relationship");
+
+ List<Pair<Vertex, Vertex>> addEdges = new ArrayList<>();
+ List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
+
+ for (Object relationship : relationships) {
+ Edge e = null;
+ Vertex cousinVertex = null;
+ Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+ if (results.isEmpty()) {
+ final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
+ ex.getTemplateVars().add(parser.getResultType());
+ ex.getTemplateVars().add(parser.getUri().toString());
+ throw ex;
+ } else {
+ //still an issue if there's more than one
+ cousinVertex = results.get(0);
+ }
+
+ if (cousinVertex != null) {
+ try {
+ if (!edgeRules.hasEdgeRule(v, cousinVertex)) {
+ throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + v.property(AAIProperties.NODE_TYPE).value().toString() + ", "
+ + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString() + ".");
+ }
+ e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex);
+
+ if (e == null) {
+ addEdges.add(new Pair<>(v, cousinVertex));
+ } else {
+ existingEdges.remove(e);
+ }
+ } catch (NoEdgeRuleFoundException e1) {
+ throw new AAIException("AAI_6145");
+ }
+ }
+ }
+
+ for (Edge edge : existingEdges) {
+ edge.remove();
+ }
+ for (Pair<Vertex, Vertex> pair : addEdges) {
+ try {
+ edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), pair.getValue0(), pair.getValue1());
+ } catch (NoEdgeRuleFoundException e) {
+ throw new AAIException("AAI_6129", e);
+ }
+ }
+
+ }
+
+ /**
+ * Write through defaults.
+ *
+ * @param v the v
+ * @param obj the obj
+ * @throws AAIUnknownObjectException
+ */
+ private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
+ Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
+ if (latest != null) {
+ Set<String> required = latest.getRequiredProperties();
+
+ for (String field : required) {
+ String defaultValue = null;
+ Object vertexProp = null;
+ defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
+ if (defaultValue != null) {
+ vertexProp = v.<Object>property(field).orElse(null);
+ if (vertexProp == null) {
+ v.property(field, defaultValue);
+ }
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Reflect dependent vertex.
+ *
+ * @param v the v
+ * @param dependentObj the dependent obj
+ * @return the vertex
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
+ //List<Vertex> items = p.getQuery().toList();
+ QueryBuilder query = this.engine.getQueryBuilder(v);
+ query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
+ query.createKeyQuery(dependentObj);
+
+ List<Vertex> items = query.toList();
+
+ Vertex dependentVertex = null;
+ if (items.size() == 1) {
+ dependentVertex = items.get(0);
+ this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
+ } else {
+ this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
+ dependentVertex = createNewVertex(dependentObj);
+ }
+
+ return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
+
+ }
+
+ /**
+ * Reflect dependent vertex.
+ *
+ * @param parent the parent
+ * @param child the child
+ * @param obj the obj
+ * @return the vertex
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
+ if (parentUri != null) {
+ String uri;
+ uri = obj.getURI();
+ child.property(AAIProperties.AAI_URI, parentUri + uri);
+ }
+ processObject(obj, child, requestContext);
+
+ Edge e;
+ e = this.getEdgeBetween(EdgeType.TREE, parent, child);
+ if (e == null) {
+ String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
+ if (canBeLinked != null && canBeLinked.equals("true")) {
+ boolean isFirst = !this.engine.getQueryBuilder(parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
+ if (isFirst) {
+ child.property(AAIProperties.LINKED, true);
+ }
+ }
+ edgeRules.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
+ }
+ return child;
+
+ }
+
+ /**
+ * Db to object.
+ *
+ * @param vertices the vertices
+ * @param obj the obj
+ * @param depth the depth
+ * @param cleanUp the clean up
+ * @return the introspector
+ * @throws AAIException the AAI exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
+
+ final int internalDepth;
+ if (depth == Integer.MAX_VALUE) {
+ internalDepth = depth--;
+ } else {
+ internalDepth = depth;
+ }
+ if (vertices.size() > 1 && !obj.isContainer()) {
+ throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
+ } else if (obj.isContainer()) {
+ final List getList;
+ String listProperty = null;
+ for (String property : obj.getProperties()) {
+ if (obj.isListType(property) && obj.isComplexGenericType(property)) {
+ listProperty = property;
+ break;
+ }
+ }
+ final String propertyName = listProperty;
+ getList = (List)obj.getValue(listProperty);
+
+ /* This is an experimental multithreading experiment
+ * on get alls.
+ */
+ ExecutorService pool = GetAllPool.getInstance().getPool();
+
+ List<Future<Object>> futures = new ArrayList<>();
+ for (Vertex v : vertices) {
+ Callable<Object> task = () -> {
+ Set<Vertex> seen = new HashSet<>();
+ Introspector childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, internalDepth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
+ dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
+ return childObject.getUnderlyingObject();
+ //getList.add(childObject.getUnderlyingObject());
+ };
+ futures.add(pool.submit(task));
+ }
+
+ for (Future<Object> future : futures) {
+ try {
+ getList.add(future.get());
+ } catch (ExecutionException e) {
+ throw new AAIException("AAI_4000", e);
+ } catch (InterruptedException e) {
+ throw new AAIException("AAI_4000", e);
+ }
+ }
+ } else if (vertices.size() == 1) {
+ Set<Vertex> seen = new HashSet<>();
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree);
+ dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
+ } else {
+ //obj = null;
+ }
+
+
+ return obj;
+ }
+
+ /**
+ * Db to object.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @param seen the seen
+ * @param depth the depth
+ * @param cleanUp the clean up
+ * @return the introspector
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
+
+ if (depth < 0) {
+ return null;
+ }
+ depth--;
+ seen.add(v);
+
+ boolean modified = false;
+ for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
+ List<Object> getList = null;
+ Vertex[] vertices = null;
+
+ if (!(obj.isComplexType(property) || obj.isListType(property))) {
+ this.copySimpleProperty(property, obj, v);
+ modified = true;
+ } else {
+ if (obj.isComplexType(property)) {
+ /* container case */
+
+ if (!property.equals("relationship-list") && depth >= 0) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
+ Object result = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp);
+ if (result != null) {
+ obj.setValue(property, argumentObject.getUnderlyingObject());
+ modified = true;
+ }
+ } else if (property.equals("relationship-list") && !nodeOnly){
+ /* relationships need to be handled correctly */
+ Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
+ relationshipList = createRelationshipList(v, relationshipList, cleanUp);
+ if (relationshipList != null) {
+ modified = true;
+ obj.setValue(property, relationshipList.getUnderlyingObject());
+ modified = true;
+ }
+
+ }
+ } else if (obj.isListType(property)) {
+
+ if (property.equals("any")) {
+ continue;
+ }
+ String genericType = obj.getGenericTypeClass(property).getSimpleName();
+ if (obj.isComplexGenericType(property) && depth >= 0) {
+ final String childDbName = convertFromCamelCase(genericType);
+ String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ EdgeRule rule;
+
+ rule = edgeRules.getEdgeRule(EdgeType.TREE, vType, childDbName);
+ if (!rule.getContains().equals(AAIDirection.NONE.toString())) {
+ //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
+ Direction ruleDirection = rule.getDirection();
+ Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
+ List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
+ itr = verticesList.stream().filter(item -> {
+ return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
+ }).iterator();
+ if (itr.hasNext()) {
+ getList = (List<Object>)obj.getValue(property);
+ }
+ int processed = 0;
+ int removed = 0;
+ while (itr.hasNext()) {
+ Vertex childVertex = itr.next();
+ if (!seen.contains(childVertex)) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
+
+ Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
+ if (result != null && getList != null) {
+ getList.add(argumentObject.getUnderlyingObject());
+ }
+
+ processed++;
+ } else {
+ removed++;
+ LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
+ }
+ }
+ if (processed == 0) {
+ //vertices were all seen, reset the list
+ getList = null;
+ }
+ if (processed > 0) {
+ modified = true;
+ }
+ }
+ } else if (obj.isSimpleGenericType(property)) {
+ List<Object> temp = this.engine.getListProperty(v, property);
+ if (temp != null) {
+ getList = (List<Object>)obj.getValue(property);
+ getList.addAll(temp);
+ modified = true;
+ }
+
+ }
+
+ }
+
+ }
+ }
+
+ //no changes were made to this obj, discard the instance
+ if (!modified) {
+ return null;
+ }
+ this.enrichData(obj, v);
+ return obj;
+
+ }
+
+
+ public Introspector getVertexProperties(Vertex v) throws AAIException, UnsupportedEncodingException {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (nodeType == null) {
+ throw new AAIException("AAI_6143");
+ }
+ Introspector obj = this.latestLoader.introspectorFromName(nodeType);
+ Set<Vertex> seen = new HashSet<>();
+ int depth = 0;
+ String cleanUp = "false";
+ boolean nodeOnly = true;
+ this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
+
+ return obj;
+
+ }
+ public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (nodeType == null) {
+ throw new AAIException("AAI_6143");
+ }
+ Introspector obj = this.latestLoader.introspectorFromName(nodeType);
+ Set<Vertex> seen = new HashSet<>();
+ int depth = AAIProperties.MAXIMUM_DEPTH;
+ String cleanUp = "false";
+ boolean nodeOnly = false;
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
+ this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
+
+ return obj;
+ }
+ /**
+ * Copy simple property.
+ *
+ * @param property the property
+ * @param obj the obj
+ * @param v the v
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ */
+ private void copySimpleProperty(String property, Introspector obj, Vertex v) {
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
+ String dbPropertyName = property;
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+ final Object temp = v.<Object>property(dbPropertyName).orElse(null);
+ if (temp != null) {
+
+ obj.setValue(property, temp);
+ }
+ }
+
+ /**
+ * Simple db to object.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ */
+ private void simpleDbToObject (Introspector obj, Vertex v) {
+ for (String property : obj.getProperties()) {
+
+
+ if (!(obj.isComplexType(property) || obj.isListType(property))) {
+ this.copySimpleProperty(property, obj, v);
+ }
+ }
+ }
+
+ /**
+ * Creates the relationship list.
+ *
+ * @param v the v
+ * @param obj the obj
+ * @param cleanUp the clean up
+ * @return the object
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws URISyntaxException
+ */
+ private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
+
+
+ List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v);
+
+ List<Object> relationshipObjList = obj.getValue("relationship");
+
+ for (Vertex cousin : cousins) {
+
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp);
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+
+ }
+
+ if (relationshipObjList.isEmpty()) {
+ return null;
+ } else {
+ return obj;
+ }
+ }
+
+ /**
+ * Process edge relationship.
+ *
+ * @param relationshipObj the relationship obj
+ * @param edge the edge
+ * @param direction the direction
+ * @param cleanUp the clean up
+ * @return the object
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp) throws UnsupportedEncodingException, AAIUnknownObjectException {
+
+
+ //we must look up all parents in this case because we need to compute name-properties
+ //we cannot used the cached aaiUri to perform this action currently
+ Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp));
+ //damaged vertex found, ignore
+ if (!tuple.isPresent()) {
+ return null;
+ }
+ List<Introspector> list = tuple.get().getValue1();
+ URI uri = this.getURIFromList(list);
+
+ URIToRelationshipObject uriParser = null;
+ Introspector result = null;
+ try {
+ uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
+ result = uriParser.getResult();
+ } catch (AAIException | URISyntaxException e) {
+ LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.get().getValue0().id().toString() + ": " + e.getMessage(), e);
+ if ("true".equals(cleanUp)) {
+ this.deleteWithTraversal(tuple.get().getValue0());
+ }
+ return null;
+ }
+
+ if(list.size() > 0 && this.version.compareTo(Version.v8) >= 0){
+ this.addRelatedToProperty(result, list.get(0));
+ }
+
+ return result.getUnderlyingObject();
+ }
+
+ /**
+ * Gets the URI for vertex.
+ *
+ * @param v the v
+ * @return the URI for vertex
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
+
+ return getURIForVertex(v, false);
+ }
+
+ public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
+ URI uri = UriBuilder.fromPath("/unknown-uri").build();
+
+ String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
+
+ if (aaiUri != null && !overwrite) {
+ uri = UriBuilder.fromPath(aaiUri).build();
+ } else {
+ Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(this.loader, v, false);
+ if (tuple.isPresent()) {
+ List<Introspector> list = tuple.get().getValue1();
+ uri = this.getURIFromList(list);
+ }
+ }
+ return uri;
+ }
+ /**
+ * Gets the URI from list.
+ *
+ * @param list the list
+ * @return the URI from list
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
+ String uri = "";
+ StringBuilder sb = new StringBuilder();
+ for (Introspector i : list) {
+ sb.insert(0, i.getURI());
+ }
+
+ uri = sb.toString();
+ URI result = UriBuilder.fromPath(uri).build();
+ return result;
+ }
+
+ /**
+ * Gets the parents.
+ *
+ * @param start the start
+ * @param removeDamaged the remove damaged
+ * @return the parents
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIUnknownObjectException
+ */
+ private Optional<Pair<Vertex, List<Introspector>>> getParents(Loader loader, Vertex start, boolean removeDamaged) {
+
+ List<Vertex> results = this.engine.getQueryEngine().findParents(start);
+ List<Introspector> objs = new ArrayList<>();
+ boolean shortCircuit = false;
+ for (Vertex v : results) {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ Introspector obj = null;
+ //vertex on the other end of this edge is bad
+ if (nodeType == null) {
+ //log something here about what was found and that it was removed
+ ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString());
+ if (removeDamaged) {
+ this.deleteWithTraversal(v);
+ }
+ shortCircuit = true;
+ } else {
+ try {
+ obj = loader.introspectorFromName(nodeType);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion());
+ obj = null;
+ }
+ }
+
+ if (obj == null) {
+ //can't make a valid path because we don't understand this object
+ // don't include it
+ } else {
+ this.simpleDbToObject(obj, v);
+ objs.add(obj);
+ }
+ }
+
+ //stop processing and don't return anything for this bad vertex
+ if (shortCircuit) {
+ return Optional.empty();
+ }
+
+ return Optional.of(new Pair<>(results.get(results.size()-1), objs));
+ }
+ /**
+ * Takes a list of vertices and a list of objs and assumes they are in
+ * the order you want the URIs to be nested.
+ * [A,B,C] creates uris [A, AB, ABC]
+ * @param vertices
+ * @param objs
+ * @throws UnsupportedEncodingException
+ * @throws URISyntaxException
+ */
+ public void setCachedURIs(List<Vertex> vertices, List<Introspector> objs) throws UnsupportedEncodingException, URISyntaxException {
+
+ String uriChain = "";
+ for (int i = 0; i < vertices.size(); i++) {
+ String aaiUri = "";
+ Vertex v = null;
+ v = vertices.get(i);
+ aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
+ if (aaiUri != null) {
+ uriChain += aaiUri;
+ } else {
+ URI uri = UriBuilder.fromPath(objs.get(i).getURI()).build();
+ aaiUri = uri.toString();
+ uriChain += aaiUri;
+ v.property(AAIProperties.AAI_URI, uriChain);
+ }
+ }
+
+
+
+ }
+
+
+ /**
+ * Adds the r
+ * @throws AAIUnknownObjectException
+ * @throws IllegalArgumentException elated to property.
+ *
+ * @param relationship the relationship
+ * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
+ */
+ public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
+ String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
+ List<Introspector> relatedToProperties = new ArrayList<>();
+
+ if (nameProps != null) {
+ String[] props = nameProps.split(",");
+ for (String prop : props) {
+ Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
+ relatedTo.setValue("property-key", child.getDbName() + "." + prop);
+ relatedTo.setValue("property-value", child.getValue(prop));
+ relatedToProperties.add(relatedTo);
+ }
+ }
+
+ if (relatedToProperties.size() > 0) {
+ List relatedToList = (List)relationship.getValue("related-to-property");
+ for (Introspector obj : relatedToProperties) {
+ relatedToList.add(obj.getUnderlyingObject());
+ }
+ }
+
+ }
+
+ /**
+ * Creates the edge.
+ *
+ * @param relationship the relationship
+ * @param inputVertex the input vertex
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
+
+ Vertex relatedVertex = null;
+
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+ if (results.size() == 0) {
+ AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
+ e.getTemplateVars().add(parser.getResultType());
+ e.getTemplateVars().add(parser.getUri().toString());
+ throw e;
+ } else {
+ //still an issue if there's more than one
+ relatedVertex = results.get(0);
+ }
+
+ if (relatedVertex != null) {
+
+ Edge e;
+ try {
+ e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex);
+ if (e == null) {
+ edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex);
+
+ } else {
+ //attempted to link two vertexes already linked
+ }
+ } catch (NoEdgeRuleFoundException e1) {
+ throw new AAIException("AAI_6129", e1);
+ }
+
+
+
+
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the edges between.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException, NoEdgeRuleFoundException {
+
+ List<Edge> result = new ArrayList<>();
+
+ if (bVertex != null) {
+ EdgeRule rule = edgeRules.getEdgeRule(type, aVertex, bVertex);
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(rule.getLabel()).filter(__.otherV().hasId(bVertex.id()));
+ List<Edge> edges = findEdgesBetween.toList();
+ for (Edge edge : edges) {
+ if (edge.label().equals(rule.getLabel())) {
+ result.add(edge);
+ }
+ }
+
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets the edge between.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
+
+
+
+ if (bVertex != null) {
+
+ List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
+
+ if (edges.size() > 0) {
+ return edges.get(0);
+ }
+
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Delete edge.
+ *
+ * @param relationship the relationship
+ * @param inputVertex the input vertex
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
+
+ Vertex relatedVertex = null;
+
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+
+ if (results.size() == 0) {
+ return false;
+ }
+
+ relatedVertex = results.get(0);
+ Edge edge;
+ try {
+ edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex);
+ } catch (NoEdgeRuleFoundException e) {
+ throw new AAIException("AAI_6129", e);
+ }
+ if (edge != null) {
+ edge.remove();
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
+ /**
+ * Delete items with traversal.
+ *
+ * @param vertexes the vertexes
+ * @throws IllegalStateException the illegal state exception
+ */
+ public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
+ for (Vertex v : vertexes) {
+ LOGGER.debug("About to delete the vertex with id: " + v.id());
+ deleteWithTraversal(v);
+ }
+ }
+
+ /**
+ * Delete with traversal.
+ *
+ * @param startVertex the start vertex
+ */
+ public void deleteWithTraversal(Vertex startVertex) {
+
+ List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
+
+ for (Vertex v : results) {
+ LOGGER.warn("Removing vertex " + v.id().toString());
+
+ v.remove();
+ }
+
+ }
+
+ /**
+ * Delete.
+ *
+ * @param v the v
+ * @param resourceVersion the resource version
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws InterruptedException the interrupted exception
+ */
+ public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
+
+ boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
+ if (result) {
+ try {
+ deleteWithTraversal(v);
+ } catch (IllegalStateException e) {
+ throw new AAIException("AAI_6110", e);
+ }
+
+ }
+
+ }
+
+
+ /**
+ * Verify delete semantics.
+ *
+ * @param vertex the vertex
+ * @param resourceVersion the resource version
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
+ boolean result = true;
+ String nodeType = "";
+ String errorDetail = " unknown delete semantic found";
+ String aaiExceptionCode = "";
+ nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
+ }
+ List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertex).union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE), __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE)).dedup().toList();
+
+ if (preventDeleteVertices.size() > 0) {
+ aaiExceptionCode = "AAI_6110";
+ errorDetail = String.format("Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types %s", preventDeleteVertices);
+ result = false;
+ }
+ if (!result) {
+ throw new AAIException(aaiExceptionCode, errorDetail);
+ }
+ return result;
+ }
+
+ /**
+ * Verify resource version.
+ *
+ * @param action the action
+ * @param nodeType the node type
+ * @param currentResourceVersion the current resource version
+ * @param resourceVersion the resource version
+ * @param uri the uri
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
+ String enabled = "";
+ String errorDetail = "";
+ String aaiExceptionCode = "";
+ if (currentResourceVersion == null) {
+ currentResourceVersion = "";
+ }
+
+ if (resourceVersion == null) {
+ resourceVersion = "";
+ }
+ try {
+ enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
+ } catch (AAIException e) {
+ ErrorLogHelper.logException(e);
+ }
+ // We're only doing the resource version checks for v5 and later
+ if (enabled.equals("true") && this.version.compareTo(Version.v8) > 0) {
+ if (!currentResourceVersion.equals(resourceVersion)) {
+ if (action.equals("create") && !resourceVersion.equals("")) {
+ errorDetail = "resource-version passed for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6135";
+ } else if (resourceVersion.equals("")) {
+ errorDetail = "resource-version not passed for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6130";
+ } else {
+ errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6131";
+ }
+
+ throw new AAIException(aaiExceptionCode, errorDetail);
+
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convert from camel case.
+ *
+ * @param name the name
+ * @return the string
+ */
+ private String convertFromCamelCase (String name) {
+ String result = "";
+ result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
+
+ NamingExceptions exceptions = NamingExceptions.getInstance();
+ result = exceptions.getDBName(result);
+
+ return result;
+ }
+
+ private boolean canModify(Introspector obj, String propName, String requestContext) {
+ final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
+ if (readOnly != null) {
+ final String[] items = readOnly.split(",");
+ for (String item : items) {
+ if (requestContext.equals(item)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataCopy.class).build();
+
+ runner.execute(obj, self);
+ }
+
+ private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
+
+ runner.execute(obj, self);
+ }
+
+ private void enrichData(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
+
+ runner.execute(obj, self);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/DeleteSemantic.java b/aai-core/src/main/java/org/onap/aai/serialization/db/DeleteSemantic.java
new file mode 100644
index 00000000..a6fe22b8
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/DeleteSemantic.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+
+/**
+ * Possible values for deleteScope can be:
+ * USE_DEFAULT - Get the scope from ref data for this node
+ * THIS_NODE_ONLY (but should fail if it there are nodes that depend on it for uniqueness)
+ * CASCADE_TO_CHILDREN - will look for OUT-Edges that have parentOf/hasDelTarget = true and follow those down
+ * ERROR_4_IN_EDGES_OR_CASCADE - combo of error-if-any-IN-edges + CascadeToChildren
+ * ERROR_IF_ANY_IN_EDGES - Fail if this node has any existing IN edges
+ * ERROR_IF_ANY_EDGES - Fail if this node has any existing edges at all!
+ */
+public enum DeleteSemantic {
+ USE_DEFAULT,
+ THIS_NODE_ONLY,
+ CASCADE_TO_CHILDREN,
+ ERROR_4_IN_EDGES_OR_CASCADE,
+ ERROR_IF_ANY_IN_EDGES,
+ ERROR_IF_ANY_EDGES,
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperties.java b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperties.java
new file mode 100644
index 00000000..73ece7e4
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperties.java
@@ -0,0 +1,44 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+public class EdgeProperties {
+
+ public static String out(EdgeProperty prop) {
+
+ return out(prop.toString());
+ }
+
+ public static String in(EdgeProperty prop) {
+ return in(prop.toString());
+ }
+
+ public static String out(String prop) {
+
+ return prop;
+ }
+
+ public static String in(String prop) {
+ return prop + "-REV";
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperty.java b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperty.java
new file mode 100644
index 00000000..29d82298
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeProperty.java
@@ -0,0 +1,45 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+public enum EdgeProperty {
+ FROM("from"),
+ TO("to"),
+ LABEL("label"),
+ DIRECTION("direction"),
+ MULTIPLICITY("multiplicity"),
+ CONTAINS("contains-other-v"),
+ DELETE_OTHER_V("delete-other-v"),
+ SVC_INFRA("SVC-INFRA"),
+ PREVENT_DELETE("prevent-delete");
+
+ private final String name;
+
+ private EdgeProperty(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgePropertyMap.java b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgePropertyMap.java
new file mode 100644
index 00000000..92643bcf
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgePropertyMap.java
@@ -0,0 +1,60 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class EdgePropertyMap<K, V> extends HashMap<K, V> {
+
+ private static final long serialVersionUID = -8298355506617458683L;
+
+ private static final Pattern variablePattern = Pattern.compile("(!)?\\$\\{(\\w+)\\}");
+
+ @Override
+ public V get(Object arg0) {
+
+ V value = super.get(arg0);
+
+ Matcher m = variablePattern.matcher(value.toString());
+ if (m.find()) {
+ if (m.groupCount() == 2) {
+ if (m.group(1) == null) {
+ value = super.get(m.group(2));
+ } else {
+ value = reverse(super.get(m.group(2)));
+ }
+ }
+ }
+
+ return value;
+ }
+
+
+ protected V reverse(V value) {
+
+ return (V)Direction.valueOf(value.toString()).opposite().toString();
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRule.java b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRule.java
new file mode 100644
index 00000000..309dbffe
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRule.java
@@ -0,0 +1,211 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class EdgeRule {
+
+ private String label = "";
+ private MultiplicityRule multiplicityRule = null;
+ private Direction direction = null;
+ private Map<EdgeProperty, String> edgeProperties = null;
+
+ /**
+ * Instantiates a new edge rule.
+ */
+ public EdgeRule() {
+ edgeProperties = new HashMap<>();
+ }
+
+ /**
+ * Gets the label.
+ *
+ * @return the label
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Sets the label.
+ *
+ * @param label the new label
+ */
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Gets the multiplicity rule.
+ *
+ * @return the multiplicity rule
+ */
+ public MultiplicityRule getMultiplicityRule() {
+ return multiplicityRule;
+ }
+
+ public void setMultiplicityRule(String multiplicity){
+ if ("Many2Many".equalsIgnoreCase(multiplicity)) {
+ this.multiplicityRule = MultiplicityRule.MANY2MANY;
+ } else if ("One2Many".equalsIgnoreCase(multiplicity)) {
+ this.multiplicityRule = MultiplicityRule.ONE2MANY;
+ } else if ("One2One".equalsIgnoreCase(multiplicity)) {
+ this.multiplicityRule = MultiplicityRule.ONE2ONE;
+ } else { //should be "Many2One"
+ this.multiplicityRule = MultiplicityRule.MANY2ONE;
+ }
+ }
+
+ /**
+ * Sets the multiplicity rule.
+ *
+ * @param multiplicityRule the new multiplicity rule
+ */
+ public void setMultiplicityRule(MultiplicityRule multiplicityRule) {
+ this.multiplicityRule = multiplicityRule;
+ }
+
+ /**
+ * Gets the direction.
+ *
+ * @return the direction
+ */
+ public Direction getDirection() {
+ return direction;
+ }
+
+ public void setDirection(String direction){
+ if ("OUT".equalsIgnoreCase(direction)) {
+ this.direction = Direction.OUT;
+ } else if ("IN".equalsIgnoreCase(direction)) {
+ this.direction = Direction.IN;
+ } else {
+ this.direction = Direction.BOTH;
+ }
+ }
+
+ /**
+ * Sets the direction.
+ *
+ * @param direction the new direction
+ */
+ public void setDirection(Direction direction) {
+ this.direction = direction;
+ }
+
+ /**
+ * Gets the checks if is parent.
+ *
+ * @return the checks if is parent
+ */
+ public String getContains() {
+ return this.getProp(EdgeProperty.CONTAINS);
+ }
+
+ /**
+ * Sets the checks if is parent.
+ *
+ * @param isParent the new checks if is parent
+ */
+ public void setContains(String isParent) {
+ this.setProp(EdgeProperty.CONTAINS, isParent);
+ }
+
+ /**
+ * Gets the checks for del target.
+ *
+ * @return the checks for del target
+ */
+ public String getDeleteOtherV() {
+ return this.getProp(EdgeProperty.DELETE_OTHER_V);
+ }
+
+ /**
+ * Sets the checks for del target.
+ *
+ * @param hasDelTarget the new checks for del target
+ */
+ public void setDeleteOtherV(String hasDelTarget) {
+ this.setProp(EdgeProperty.DELETE_OTHER_V, hasDelTarget);
+ }
+
+ /**
+ * Gets the service infrastructure.
+ *
+ * @return the service infrastructure
+ */
+ public String getServiceInfrastructure() {
+ return this.getProp(EdgeProperty.SVC_INFRA);
+ }
+
+ /**
+ * Sets the service infrastructure.
+ *
+ * @param serviceInfrastructure the new service infrastructure
+ */
+ public void setServiceInfrastructure(String serviceInfrastructure) {
+ this.setProp(EdgeProperty.SVC_INFRA, serviceInfrastructure);
+ }
+
+ public String getPreventDelete() {
+ return this.getProp(EdgeProperty.PREVENT_DELETE);
+ }
+
+ public void setPreventDelete(String preventDelete) {
+ this.setProp(EdgeProperty.PREVENT_DELETE, preventDelete);
+ }
+
+ /**
+ * Gets the edge properties.
+ *
+ * @return the edge properties
+ */
+ public Map<EdgeProperty, String> getEdgeProperties() {
+ return this.edgeProperties;
+ }
+
+ /**
+ * Sets the prop.
+ *
+ * @param key the key
+ * @param value the value
+ */
+ private void setProp(EdgeProperty key, String value) {
+ this.edgeProperties.put(key, value);
+ }
+
+ /**
+ * Gets the prop.
+ *
+ * @param key the key
+ * @return the prop
+ */
+ private String getProp(EdgeProperty key) {
+ return this.edgeProperties.get(key);
+ }
+
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java
new file mode 100644
index 00000000..d9dfa457
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeRules.java
@@ -0,0 +1,589 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+import static com.jayway.jsonpath.Criteria.where;
+import static com.jayway.jsonpath.Filter.filter;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
+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.exceptions.AAIException;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.serialization.db.exceptions.EdgeMultiplicityException;
+import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import com.jayway.jsonpath.DocumentContext;
+import com.jayway.jsonpath.Filter;
+import com.jayway.jsonpath.JsonPath;
+
+public class EdgeRules {
+
+ private EELFLogger logger = EELFManager.getInstance().getLogger(EdgeRules.class);
+
+ private DocumentContext rulesDoc;
+
+ /**
+ * Loads the most recent DbEdgeRules json file for later parsing.
+ * Only need most recent version for actual A&AI operations that call this class;
+ * the old ones are only used in tests.
+ */
+ private EdgeRules() {
+
+ String json = this.getEdgeRuleJson(Version.getLatest());
+ rulesDoc = JsonPath.parse(json);
+
+ }
+
+ private EdgeRules(String rulesFilename) {
+ String json = this.getEdgeRuleJson(rulesFilename);
+ rulesDoc = JsonPath.parse(json);
+ }
+
+ private String getEdgeRuleJson(String rulesFilename) {
+ InputStream is = getClass().getResourceAsStream(rulesFilename);
+
+ Scanner scanner = new Scanner(is);
+ String json = scanner.useDelimiter("\\Z").next();
+ scanner.close();
+
+ return json;
+ }
+
+ /**
+ * Loads the versioned DbEdgeRules json file for later parsing.
+ */
+ @SuppressWarnings("unchecked")
+ private EdgeRules(Version version) {
+ String json = this.getEdgeRuleJson(version);
+ rulesDoc = JsonPath.parse(json);
+ }
+
+ private String getEdgeRuleJson(Version version) {
+ InputStream is = getClass().getResourceAsStream("/dbedgerules/DbEdgeRules_" + version.toString() + ".json");
+
+ Scanner scanner = new Scanner(is);
+ String json = scanner.useDelimiter("\\Z").next();
+ scanner.close();
+
+ return json;
+ }
+
+ private static class Helper {
+ private static final EdgeRules INSTANCE = new EdgeRules();
+ private static final Map<Version, EdgeRules> INSTANCEMAP = new ConcurrentHashMap<>();
+
+ private static EdgeRules getEdgeRulesByFilename(String rulesFilename) {
+ return new EdgeRules(rulesFilename);
+ }
+
+ private static EdgeRules getVersionedEdgeRules(Version v) {
+ if (Version.isLatest(v)) {
+ return INSTANCE;
+ }
+ if (!INSTANCEMAP.containsKey(v)) {
+ INSTANCEMAP.put(v, new EdgeRules(v));
+ }
+ return INSTANCEMAP.get(v);
+ }
+ }
+
+ /**
+ * Gets the single instance of EdgeRules.
+ *
+ * @return single instance of EdgeRules
+ */
+ public static EdgeRules getInstance() {
+ return Helper.INSTANCE;
+
+ }
+
+ /**
+ * Gets the versioned instance of EdgeRules.
+ *
+ * @return versioned instance of EdgeRules
+ */
+ public static EdgeRules getInstance(Version v) {
+ return Helper.getVersionedEdgeRules(v);
+
+ }
+
+ /**
+ * Loads edge rules from the given file.
+ *
+ * @param rulesFilename - name of the file to load rules from
+ * @return the EdgeRules instance
+ */
+ public static EdgeRules getInstance(String rulesFilename) {
+ return Helper.getEdgeRulesByFilename(rulesFilename);
+ }
+
+ /**
+ * Adds the tree edge.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ */
+ public Edge addTreeEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, false);
+ }
+
+ /**
+ * Adds the edge.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ */
+ public Edge addEdge(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, false);
+ }
+
+ /**
+ * Adds the tree edge.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ */
+ public Edge addTreeEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.addEdge(EdgeType.TREE, traversalSource, aVertex, bVertex, true);
+ }
+
+ /**
+ * Adds the edge.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ */
+ public Edge addEdgeIfPossible(GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.addEdge(EdgeType.COUSIN, traversalSource, aVertex, bVertex, true);
+ }
+
+ /**
+ * Adds the edge.
+ *
+ * @param type the type
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edge
+ * @throws AAIException the AAI exception
+ */
+ private Edge addEdge(EdgeType type, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex, boolean isBestEffort) throws AAIException {
+
+ EdgeRule rule = this.getEdgeRule(type, aVertex, bVertex);
+
+ Edge e = null;
+
+ Optional<String> message = this.validateMultiplicity(rule, traversalSource, aVertex, bVertex);
+
+ if (message.isPresent() && !isBestEffort) {
+ throw new EdgeMultiplicityException(message.get());
+ }
+ if (!message.isPresent()) {
+ if (rule.getDirection().equals(Direction.OUT)) {
+ e = aVertex.addEdge(rule.getLabel(), bVertex);
+ } else if (rule.getDirection().equals(Direction.IN)) {
+ e = bVertex.addEdge(rule.getLabel(), aVertex);
+ }
+
+ this.addProperties(e, rule);
+ }
+ return e;
+ }
+
+ /**
+ * Adds the properties.
+ *
+ * @param edge the edge
+ * @param rule the rule
+ */
+ public void addProperties(Edge edge, EdgeRule rule) {
+
+ // In DbEdgeRules.EdgeRules -- What we have as "edgeRule" is a comma-delimited set of strings.
+ // The first item is the edgeLabel.
+ // The second in the list is always "direction" which is always OUT for the way we've implemented it.
+ // Items starting at "firstTagIndex" and up are all assumed to be booleans that map according to
+ // tags as defined in EdgeInfoMap.
+ // Note - if they are tagged as 'reverse', that means they get the tag name with "-REV" on it
+ Map<EdgeProperty, String> propMap = rule.getEdgeProperties();
+
+ for (Entry<EdgeProperty, String> entry : propMap.entrySet()) {
+ edge.property(entry.getKey().toString(), entry.getValue());
+ }
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given nodes, in either A|B or B|A order.
+ *
+ * @param nodeA - node at one end of the edge
+ * @param nodeB - node at the other end
+ * @return true, if any such rules exist
+ */
+ public boolean hasEdgeRule(String nodeA, String nodeB) {
+ Filter aToB = filter(
+ where("from").is(nodeA).and("to").is(nodeB)
+ );
+ Filter bToA = filter(
+ where("from").is(nodeB).and("to").is(nodeA)
+ );
+
+ List<Map<String, String>> results = readRules(aToB);
+ results.addAll(readRules(bToA));
+
+ return !results.isEmpty();
+
+ }
+
+ /**
+ * Checks if any edge rules exist between the two given nodes, in either A|B or B|A order.
+ *
+ * @param aVertex - node at one end of the edge
+ * @param bVertex - node at the other end
+ * @return true, if any such rules exist
+ */
+ public boolean hasEdgeRule(Vertex aVertex, Vertex bVertex) {
+ String outType = aVertex.<String>property("aai-node-type").orElse(null);
+ String inType = bVertex.<String>property("aai-node-type").orElse(null);
+
+ return this.hasEdgeRule(outType, inType);
+
+ }
+
+ /**
+ * Gets all the edge rules that exist between the given node types.
+ * The rules will be phrased in terms of out|in, though this will
+ * also find rules defined as in|out (it will flip the direction in
+ * the EdgeRule object returned accordingly to match out|in).
+ *
+ * @param outType
+ * @param inType
+ * @return Map<String edgeLabel, EdgeRule rule> where edgeLabel is the label name
+ * @throws AAIException
+ */
+ public Map<String, EdgeRule> getEdgeRules(String outType, String inType) throws AAIException {
+ Map<String, EdgeRule> result = new HashMap<>();
+ EdgeRule rule = null;
+ for (EdgeType type : EdgeType.values()) {
+ try {
+ rule = this.getEdgeRule(type, outType, inType);
+ result.put(rule.getLabel(), rule);
+ } catch (NoEdgeRuleFoundException e) {
+ continue;
+ }
+ }
+
+ return result;
+ }
+
+
+
+ /**
+ * Gets the edge rule of the given type that exists between A and B.
+ * Will check B|A as well, and flips the direction accordingly if that succeeds
+ * to match the expected A|B return.
+ *
+ * @param type - the type of edge you're looking for
+ * @param nodeA - first node type
+ * @param nodeB - second node type
+ * @return EdgeRule describing the rule in terms of A|B, if there is any such rule
+ * @throws AAIException if no such edge exists
+ */
+ public EdgeRule getEdgeRule(EdgeType type, String nodeA, String nodeB) throws AAIException {
+ //try A to B
+ List<Map<String, String>> aToBEdges = readRules(buildFilter(type, nodeA, nodeB));
+ if (!aToBEdges.isEmpty()) {
+ //lazily stop iterating if we find a match
+ //should there be a mismatch between type and isParent,
+ //the caller will receive something.
+ //this operates on the assumption that there are at most two rules
+ //for a given vertex pair
+ verifyRule(aToBEdges.get(0));
+ return buildRule(aToBEdges.get(0));
+ }
+
+ //we get here if there was nothing for A to B, so let's try B to A
+ List<Map<String, String>> bToAEdges = readRules(buildFilter(type, nodeB, nodeA));
+ if (!bToAEdges.isEmpty()) {
+ verifyRule(bToAEdges.get(0));
+ return flipDirection(buildRule(bToAEdges.get(0))); //bc we need to return as A|B, so flip the direction to match
+ }
+
+ //found none
+ throw new NoEdgeRuleFoundException("no " + type.toString() + " edge between " + nodeA + " and " + nodeB);
+ }
+
+ /**
+ * Builds a JsonPath filter to search for an edge from nodeA to nodeB with the given edge type (cousin or parent/child)
+ *
+ * @param type
+ * @param nodeA - start node
+ * @param nodeB - end node
+ * @return
+ */
+ private Filter buildFilter(EdgeType type, String nodeA, String nodeB) {
+ if (EdgeType.COUSIN.equals(type)) {
+ return filter(
+ where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is(AAIDirection.NONE.toString())
+ );
+ } else {
+ return filter(
+ where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is("${direction}")).or(
+ where("from").is(nodeA).and("to").is(nodeB).and(EdgeProperty.CONTAINS.toString()).is("!${direction}")
+ );
+ }
+ }
+
+ /**
+ * Puts the give edge rule information into an EdgeRule object.
+ *
+ * @param edge - the edge information returned from JsonPath
+ * @return EdgeRule containing that information
+ */
+ private EdgeRule buildRule(Map<String, String> map) {
+ Map<String, String> edge = new EdgePropertyMap<>();
+ edge.putAll(map);
+
+ EdgeRule rule = new EdgeRule();
+ rule.setLabel(edge.get("label"));
+ rule.setDirection(edge.get("direction"));
+ rule.setMultiplicityRule(edge.get("multiplicity"));
+ rule.setContains(edge.get(EdgeProperty.CONTAINS.toString()));
+ rule.setDeleteOtherV(edge.get(EdgeProperty.DELETE_OTHER_V.toString()));
+ rule.setServiceInfrastructure(edge.get(EdgeProperty.SVC_INFRA.toString()));
+ rule.setPreventDelete(edge.get(EdgeProperty.PREVENT_DELETE.toString()));
+
+ return rule;
+ }
+
+ /**
+ * If getEdgeRule gets a request for A|B, and it finds something as B|A, the caller still expects
+ * the returned EdgeRule to reflect A|B directionality. This helper method flips B|A direction to
+ * match this expectation.
+ *
+ * @param rule whose direction needs flipped
+ * @return the updated rule
+ */
+ private EdgeRule flipDirection(EdgeRule rule) {
+ if (Direction.IN.equals(rule.getDirection())) {
+ rule.setDirection(Direction.OUT);
+ return rule;
+ } else if (Direction.OUT.equals(rule.getDirection())) {
+ rule.setDirection(Direction.IN);
+ return rule;
+ } else { //direction is BOTH, flipping both is still both
+ return rule;
+ }
+ }
+
+ /**
+ * Gets the edge rule of the given type that exists between A and B.
+ * Will check B|A as well, and flips the direction accordingly if that succeeds
+ * to match the expected A|B return.
+ *
+ * @param type - the type of edge you're looking for
+ * @param aVertex - first node type
+ * @param bVertex - second node type
+ * @return EdgeRule describing the rule in terms of A|B, if there is any such rule
+ * @throws AAIException if no such edge exists
+ */
+ public EdgeRule getEdgeRule(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
+ String outType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String inType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+
+ return this.getEdgeRule(type, outType, inType);
+
+
+ }
+
+ /**
+ * Validate multiplicity.
+ *
+ * @param rule the rule
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private Optional<String> validateMultiplicity(EdgeRule rule, GraphTraversalSource traversalSource, Vertex aVertex, Vertex bVertex) {
+
+ if (rule.getDirection().equals(Direction.OUT)) {
+
+ } else if (rule.getDirection().equals(Direction.IN)) {
+ Vertex tempV = bVertex;
+ bVertex = aVertex;
+ aVertex = tempV;
+ }
+
+ String aVertexType = aVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String bVertexType = bVertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ String label = rule.getLabel();
+ MultiplicityRule multiplicityRule = rule.getMultiplicityRule();
+ List<Edge> outEdges = traversalSource.V(aVertex).outE(label).where(__.inV().has(AAIProperties.NODE_TYPE, bVertexType)).toList();
+ List<Edge> inEdges = traversalSource.V(bVertex).inE(label).where(__.outV().has(AAIProperties.NODE_TYPE, aVertexType)).toList();
+ String detail = "";
+ if (multiplicityRule.equals(MultiplicityRule.ONE2ONE)) {
+ if (inEdges.size() >= 1 || outEdges.size() >= 1 ) {
+ detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ }
+ } else if (multiplicityRule.equals(MultiplicityRule.ONE2MANY)) {
+ if (inEdges.size() >= 1) {
+ detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ }
+ } else if (multiplicityRule.equals(MultiplicityRule.MANY2ONE)) {
+ if (outEdges.size() >= 1) {
+ detail = "multiplicity rule violated: only one edge can exist with label: " + label + " between " + aVertexType + " and " + bVertexType;
+ }
+ } else {
+
+ }
+
+ if (!"".equals(detail)) {
+ return Optional.of(detail);
+ } else {
+ return Optional.empty();
+ }
+
+
+ }
+
+ /**
+ * Verifies that all required properties are defined in the given edge rule.
+ * If they are not, throws a RuntimeException.
+ *
+ * @param rule - Map<String edge property, String edge property value> representing
+ * an edge rule
+ */
+ private void verifyRule(Map<String, String> rule) {
+ for (EdgeProperty prop : EdgeProperty.values()) {
+ if (!rule.containsKey(prop.toString())) {
+ /* Throws RuntimeException as rule definition errors
+ * cannot be recovered from, and should never happen anyway
+ * because these are configuration files, so requiring all
+ * downstream code to check for this exception seems inappropriate.
+ * It's instantiated with an AAIException to make sure all
+ * relevant information is present in the error message.
+ */
+ throw new RuntimeException(new AAIException("AAI_4005",
+ "Rule between " + rule.get("from") + " and " + rule.get("to") +
+ " is missing property " + prop + "."));
+ }
+ }
+ }
+
+ /**
+ * Reads all the edge rules from the loaded json file.
+ *
+ * @return List<Map<String edge property, String edge property value>>
+ * Each map represents a rule read from the json.
+ */
+ private List<Map<String, String>> readRules() {
+ return readRules(null);
+ }
+
+ /**
+ * Reads the edge rules from the loaded json file, using the given filter
+ * to get specific rules. If filter is null, will get all rules.
+ *
+ * @param filter - may be null to indicate get all
+ * @return List<Map<String edge property, String edge property value>>
+ * Each map represents a rule read from the json.
+ */
+ private List<Map<String, String>> readRules(Filter filter) {
+ List<Map<String, String>> results;
+ if (filter == null) { //no filter means get all
+ results = rulesDoc.read("$.rules.*");
+ } else {
+ results = rulesDoc.read("$.rules.[?]", filter);
+ }
+ for (Map<String, String> result : results) {
+ verifyRule(result);
+ }
+ return results;
+ }
+
+ /**
+ * Gets all the edge rules we define.
+ *
+ * @return Multimap<String "from|to", EdgeRule rule>
+ */
+ public Multimap<String, EdgeRule> getAllRules() {
+ Multimap<String, EdgeRule> result = ArrayListMultimap.create();
+
+ List<Map<String, String>> rules = readRules();
+ for (Map<String, String> rule : rules) {
+ EdgeRule er = buildRule(rule);
+ String name = rule.get("from") + "|" + rule.get("to");
+ result.put(name, er);
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets all edge rules that define a child relationship from
+ * the given node type.
+ *
+ * @param nodeType
+ * @return
+ */
+ public Set<EdgeRule> getChildren(String nodeType) {
+
+ final Filter filter = filter(
+ where("from").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is("${direction}")
+ ).or(where("to").is(nodeType).and(EdgeProperty.CONTAINS.toString()).is("!${direction}"));
+
+ final List<Map<String, String>> rules = readRules(filter);
+ final Set<EdgeRule> result = new HashSet<>();
+ rules.forEach(item -> {
+ verifyRule(item);
+ result.add(buildRule(item));
+ });
+
+ return result;
+
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeType.java b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeType.java
new file mode 100644
index 00000000..088e13bb
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/EdgeType.java
@@ -0,0 +1,27 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+public enum EdgeType {
+ COUSIN,
+ TREE;
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/GetAllPool.java b/aai-core/src/main/java/org/onap/aai/serialization/db/GetAllPool.java
new file mode 100644
index 00000000..4d38bd38
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/GetAllPool.java
@@ -0,0 +1,47 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class GetAllPool {
+
+ private ExecutorService pool;
+
+ private GetAllPool() {
+ pool = Executors.newWorkStealingPool(Runtime.getRuntime().availableProcessors());
+ }
+
+ private static class Helper {
+ private static final GetAllPool INSTANCE = new GetAllPool();
+ }
+
+ public static GetAllPool getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ public ExecutorService getPool() {
+
+ return this.pool;
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java b/aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java
new file mode 100644
index 00000000..9bb04d6b
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java
@@ -0,0 +1,70 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+import com.thinkaurelius.titan.core.TitanGraph;
+import org.onap.aai.dbmap.AAIGraph;
+import org.onap.aai.dbmap.DBConnectionType;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/* This class simply calls AAIGraph under the covers for now */
+public class GraphSingleton {
+
+ protected AtomicInteger totalCount = new AtomicInteger();
+
+ private static class Helper {
+ private static final GraphSingleton INSTANCE = new GraphSingleton();
+ }
+
+ /**
+ * Gets the single instance of GraphSingleton.
+ *
+ * @return single instance of GraphSingleton
+ */
+ public static GraphSingleton getInstance() {
+ return Helper.INSTANCE;
+
+ }
+
+ /**
+ * Gets the count.
+ *
+ * @return the count
+ */
+ public AtomicInteger getCount() {
+ return totalCount;
+ }
+
+ /**
+ * Gets the tx graph.
+ *
+ * @return the tx graph
+ */
+ public TitanGraph getTxGraph() {
+ return AAIGraph.getInstance().getGraph();
+ }
+
+ public TitanGraph getTxGraph(DBConnectionType connectionType) {
+ return AAIGraph.getInstance().getGraph(connectionType);
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/LegacyDBSerializer.java b/aai-core/src/main/java/org/onap/aai/serialization/db/LegacyDBSerializer.java
new file mode 100644
index 00000000..b9343816
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/LegacyDBSerializer.java
@@ -0,0 +1,35 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.ModelType;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+
+public class LegacyDBSerializer extends DBSerializer {
+
+ public LegacyDBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
+ super(version, engine, introspectionType, sourceOfTruth);
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/MultiplicityRule.java b/aai-core/src/main/java/org/onap/aai/serialization/db/MultiplicityRule.java
new file mode 100644
index 00000000..0451c0d7
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/MultiplicityRule.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+public enum MultiplicityRule {
+ MANY2ONE,
+ ONE2MANY,
+ ONE2ONE,
+ MANY2MANY
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/TitanGraphSingleton.java b/aai-core/src/main/java/org/onap/aai/serialization/db/TitanGraphSingleton.java
new file mode 100644
index 00000000..e1accb4e
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/TitanGraphSingleton.java
@@ -0,0 +1,39 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db;
+
+/* This is class is just a wrapper of its parent */
+public class TitanGraphSingleton extends GraphSingleton {
+
+ private static class Helper {
+ private static final TitanGraphSingleton INSTANCE = new TitanGraphSingleton();
+ }
+
+ /**
+ * Gets the single instance of TitanGraphSingleton.
+ *
+ * @return single instance of TitanGraphSingleton
+ */
+ public static TitanGraphSingleton getInstance() {
+ return Helper.INSTANCE;
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/EdgeMultiplicityException.java b/aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/EdgeMultiplicityException.java
new file mode 100644
index 00000000..6baa113d
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/EdgeMultiplicityException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db.exceptions;
+
+import org.onap.aai.exceptions.AAIException;
+
+public class EdgeMultiplicityException extends AAIException {
+
+ private static final long serialVersionUID = -5575661036426538012L;
+
+ public EdgeMultiplicityException(String message) {
+ super("AAI_6140", message);
+ }
+
+ public EdgeMultiplicityException(Throwable cause) {
+ super("AAI_6140",cause);
+ }
+
+ public EdgeMultiplicityException(String message, Throwable cause) {
+ super("AAI_6140", cause, message);
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java b/aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java
new file mode 100644
index 00000000..247379cb
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/exceptions/NoEdgeRuleFoundException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.db.exceptions;
+
+import org.onap.aai.exceptions.AAIException;
+
+public class NoEdgeRuleFoundException extends AAIException {
+
+ private static final long serialVersionUID = -906843868234976763L;
+
+ public NoEdgeRuleFoundException(String message) {
+ super("AAI_6129", message);
+ }
+
+ public NoEdgeRuleFoundException(Throwable cause) {
+ super("AAI_6129",cause);
+ }
+
+ public NoEdgeRuleFoundException(String message, Throwable cause) {
+ super("AAI_6129", cause, message);
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java
new file mode 100644
index 00000000..db947bf8
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java
@@ -0,0 +1,26 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.engines;
+
+public enum QueryStyle {
+ GREMLIN_TRAVERSAL, GREMLIN_UNIQUE, GREMLINPIPELINE_TRAVERSAL, TRAVERSAL
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/TitanDBEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/TitanDBEngine.java
new file mode 100644
index 00000000..315081e7
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/TitanDBEngine.java
@@ -0,0 +1,102 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.engines;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.serialization.db.TitanGraphSingleton;
+
+public class TitanDBEngine extends TransactionalGraphEngine {
+
+ /**
+ * Instantiates a new titan DB engine.
+ *
+ * @param style the style
+ * @param loader the loader
+ */
+ public TitanDBEngine(QueryStyle style, DBConnectionType connectionType, Loader loader) {
+ super(style, loader, connectionType, TitanGraphSingleton.getInstance());
+ }
+
+ /**
+ * Instantiates a new titan DB engine.
+ *
+ * @param style the style
+ * @param loader the loader
+ * @param connect the connect
+ */
+ public TitanDBEngine(QueryStyle style, Loader loader, boolean connect) {
+ super(style, loader);
+ if (connect) {
+ this.singleton = TitanGraphSingleton.getInstance();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean setListProperty(Vertex v, String name, List<?> objs) {
+
+ //clear out list full replace style
+
+ Iterator<VertexProperty<Object>> iterator = v.properties(name);
+ while (iterator.hasNext()) {
+ iterator.next().remove();
+ }
+ if (objs != null) {
+ for (Object obj : objs) {
+ v.property(name, obj);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Object> getListProperty(Vertex v, String name) {
+
+ List<Object> result = new ArrayList<Object>();
+
+ Iterator<VertexProperty<Object>> iterator = v.properties(name);
+
+ while (iterator.hasNext()) {
+ result.add(iterator.next().value());
+ }
+
+ if (result.size() == 0) {
+ result = null;
+ }
+
+ return result;
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java
new file mode 100644
index 00000000..11bf5955
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java
@@ -0,0 +1,246 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.engines;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.dbmap.DBConnectionType;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.query.builder.GremlinTraversal;
+import org.onap.aai.query.builder.GremlinUnique;
+import org.onap.aai.query.builder.QueryBuilder;
+import org.onap.aai.query.builder.TraversalQuery;
+import org.onap.aai.serialization.db.GraphSingleton;
+import org.onap.aai.serialization.engines.query.GraphTraversalQueryEngine;
+import org.onap.aai.serialization.engines.query.QueryEngine;
+
+import com.thinkaurelius.titan.core.TitanGraph;
+import com.thinkaurelius.titan.core.schema.TitanManagement;
+
+public abstract class TransactionalGraphEngine {
+
+ protected GraphSingleton singleton = null;
+ protected QueryEngine queryEngine = null;
+ protected QueryBuilder<Vertex> queryBuilder = null;
+ protected QueryStyle style = null;
+ protected final DBConnectionType connectionType;
+ protected final Loader loader;
+ protected Graph currentTx = null;
+ protected GraphTraversalSource currentTraversal = null;
+ protected GraphTraversalSource readOnlyTraversal = null;
+ private final Admin admin;
+ /**
+ * Instantiates a new transactional graph engine.
+ *
+ * @param style the style
+ * @param loader the loader
+ */
+ public TransactionalGraphEngine (QueryStyle style, Loader loader, DBConnectionType connectionType, GraphSingleton singleton) {
+ this.loader = loader;
+ this.style = style;
+ this.singleton = singleton;
+ this.connectionType = connectionType;
+ admin = new Admin();
+
+ }
+
+ public TransactionalGraphEngine (QueryStyle style, Loader loader) {
+ this.loader = loader;
+ this.style = style;
+ this.connectionType = DBConnectionType.REALTIME;
+ admin = new Admin();
+ }
+
+ /**
+ * Sets the list property.
+ *
+ * @param v the v
+ * @param name the name
+ * @param obj the obj
+ * @return true, if successful
+ */
+ public abstract boolean setListProperty(Vertex v, String name, List<?> obj);
+
+ /**
+ * Gets the list property.
+ *
+ * @param v the v
+ * @param name the name
+ * @return the list property
+ */
+ public abstract List<Object> getListProperty(Vertex v, String name);
+
+ /**
+ * Gets the graph.
+ *
+ * @return the graph
+ */
+ private TitanGraph getGraph() {
+ return singleton.getTxGraph(this.connectionType);
+ }
+
+ /**
+ * Gets the count.
+ *
+ * @return the count
+ */
+ public AtomicInteger getCount() {
+ return singleton.getCount();
+ }
+
+
+ /**
+ * Gets the query engine.
+ *
+ * @return the query engine
+ */
+ public QueryEngine getQueryEngine() {
+ QueryEngine engine = null;
+ if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) {
+ //this.queryEngine = new GremlinQueryEngine(this);
+ } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) {
+ //this.queryEngine = new GremlinQueryEngine(this);
+ } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) {
+ //this.queryEngine = new GremlinPipelineQueryEngine(this);
+ } else if (style.equals(QueryStyle.TRAVERSAL)) {
+
+ return new GraphTraversalQueryEngine(this.asAdmin().getTraversalSource());
+
+ } else {
+ throw new IllegalArgumentException("Query Engine type not recognized");
+ }
+
+ return engine;
+ }
+
+ /**
+ * Gets the query builder.
+ *
+ * @return the query builder
+ */
+ public QueryBuilder<Vertex> getQueryBuilder() {
+ return getQueryBuilder(this.loader);
+ }
+
+ public QueryBuilder<Vertex> getQueryBuilder(QueryStyle style) {
+ return getQueryBuilder(style, this.loader);
+ }
+
+ public QueryBuilder<Vertex> getQueryBuilder(Loader loader) {
+ return getQueryBuilder(this.style, loader);
+ }
+
+ public QueryBuilder<Vertex> getQueryBuilder(QueryStyle style, Loader loader) {
+ if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) {
+ return new GremlinTraversal<>(loader, this.asAdmin().getTraversalSource());
+ } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) {
+ return new GremlinUnique<>(loader, this.asAdmin().getTraversalSource());
+ } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) {
+ //return new GremlinPipelineTraversal(loader);
+ } else if (style.equals(QueryStyle.TRAVERSAL)) {
+ return new TraversalQuery<>(loader, this.asAdmin().getTraversalSource());
+ } else {
+ throw new IllegalArgumentException("Query Builder type not recognized");
+ }
+ return queryBuilder;
+ }
+ /**
+ * Gets the query builder.
+ *
+ * @param start the start
+ * @return the query builder
+ */
+ public QueryBuilder<Vertex> getQueryBuilder(Vertex start) {
+ return getQueryBuilder(this.loader, start);
+ }
+
+ public QueryBuilder<Vertex> getQueryBuilder(Loader loader, Vertex start) {
+ return getQueryBuilder(this.style, loader, start);
+ }
+
+ public QueryBuilder<Vertex> getQueryBuilder(QueryStyle style, Loader loader, Vertex start) {
+ if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) {
+ return new GremlinTraversal<>(loader, this.asAdmin().getTraversalSource(), start);
+ } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) {
+ return new GremlinUnique<>(loader, this.asAdmin().getTraversalSource(), start);
+ } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) {
+ //return new GremlinPipelineTraversal(loader,start);
+ } else if (style.equals(QueryStyle.TRAVERSAL)) {
+ return new TraversalQuery<>(loader, this.asAdmin().getTraversalSource(), start);
+ } else {
+ throw new IllegalArgumentException("Query Builder type not recognized");
+ }
+ return queryBuilder;
+ }
+ public Graph startTransaction() {
+ if (this.tx() == null) {
+ this.currentTx = this.getGraph().newTransaction();
+ this.currentTraversal = this.tx().traversal();
+ this.readOnlyTraversal = this.tx().traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()));
+ }
+ return currentTx;
+ }
+
+ public void rollback() {
+ if (this.tx() != null) {
+ this.tx().tx().rollback();
+ this.currentTx = null;
+ this.currentTraversal = null;
+ this.readOnlyTraversal = null;
+ }
+ }
+ public void commit() {
+ if (this.tx() != null) {
+ this.tx().tx().commit();
+ this.currentTx = null;
+ this.currentTraversal = null;
+ this.readOnlyTraversal = null;
+ }
+ }
+
+ public Graph tx() {
+ return this.currentTx;
+ }
+
+ public Admin asAdmin() {
+ return admin;
+ }
+
+ public class Admin {
+
+ public GraphTraversalSource getTraversalSource() {
+ return currentTraversal;
+ }
+ public GraphTraversalSource getReadOnlyTraversalSource() {
+ return readOnlyTraversal;
+ }
+
+ public TitanManagement getManagementSystem() {
+ return getGraph().openManagement();
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java
new file mode 100644
index 00000000..872b0c5f
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java
@@ -0,0 +1,198 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.engines.query;
+
+
+import static org.onap.aai.serialization.db.AAIDirection.IN;
+import static org.onap.aai.serialization.db.AAIDirection.NONE;
+import static org.onap.aai.serialization.db.AAIDirection.OUT;
+import static org.onap.aai.serialization.db.EdgeProperty.CONTAINS;
+import static org.onap.aai.serialization.db.EdgeProperty.DELETE_OTHER_V;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.tinkerpop.gremlin.process.traversal.P;
+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.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.introspection.Loader;
+
+/*
+ * This class needs some big explanation despite its compact size.
+ * This controls all the queries performed by the CRUD API in A&AI.
+ * findParents, findChildren, and findDeletable require special attention
+ * These methods use 'repeat'. You cannot use 'emit' with repeat currently
+ * as it is extremely buggy as of tinkerpop-3.0.1-incubating. The way around
+ * it (for now) is to sideEffect all the vertices we traverse into an ArrayList.
+ *
+ */
+public class GraphTraversalQueryEngine extends QueryEngine {
+
+ /**
+ * Instantiates a new graph traversal query engine.
+ *
+ * @param graphEngine the graph engine
+ */
+ public GraphTraversalQueryEngine(GraphTraversalSource g) {
+ super(g);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findParents(Vertex start) {
+
+ final GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).emit(v -> true).repeat(__.union(__.inE().has(CONTAINS.toString(), OUT.toString()).outV(), __.outE().has(CONTAINS.toString(), IN.toString()).inV()));
+ return pipe.toList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findAllChildren(Vertex start) {
+
+ GraphTraversal<Vertex, Vertex> pipe = this.g
+ .V(start).emit(v -> true).repeat(__.union(__.outE().has(CONTAINS.toString(), OUT.toString()).inV(), __.inE().has(CONTAINS.toString(), IN.toString()).outV()));
+
+
+ return pipe.toList();
+
+ }
+
+ public List<Vertex> findChildrenOfType(Vertex start, String type) {
+ GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).union(
+ __.outE().has(CONTAINS.toString(), OUT.toString()).inV(),
+ __.inE().has(CONTAINS.toString(), IN.toString()).outV()
+ ).has(AAIProperties.NODE_TYPE, type).dedup();
+
+ return pipe.toList();
+ }
+
+ public List<Vertex> findChildren(Vertex start) {
+ GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).union(
+ __.outE().has(CONTAINS.toString(), OUT.toString()),
+ __.inE().has(CONTAINS.toString(), IN.toString())
+ ).otherV().dedup();
+
+ return pipe.toList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findDeletable(Vertex start) {
+ GraphTraversal<Vertex, Vertex> pipe = this.g
+ .V(start).emit(v -> true).repeat(
+ __.union(
+ __.outE().or(
+ __.has(CONTAINS.toString(), OUT.toString()),
+ __.has(DELETE_OTHER_V.toString(), OUT.toString())
+ ).inV(),
+ __.inE().or(
+ __.has(CONTAINS.toString(), IN.toString()),
+ __.has(DELETE_OTHER_V.toString(), IN.toString())
+ ).outV()
+ )
+ );
+
+ return pipe.toList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) {
+ GraphTraversal<Vertex, Vertex> pipe = this.g.V(start);
+ switch (direction) {
+ case OUT:
+ pipe.out(label);
+ break;
+ case IN:
+ pipe.in(label);
+ break;
+ case BOTH:
+ pipe.both(label);
+ break;
+ default:
+ break;
+ }
+
+ pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup();
+ return pipe.toList();
+ }
+
+ @Override
+ public Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly) {
+ final GraphTraversal<Vertex, ?> t = this.g.V(start).emit(v -> true).times(iterations).repeat(
+ __.union(
+ __.outE().has(CONTAINS.toString(), OUT.toString()).inV(),
+ __.inE().has(CONTAINS.toString(), IN.toString()).outV())
+ );
+
+ if (!nodeOnly) {
+ t.union(
+ __.identity(),
+ __.bothE().has(CONTAINS.toString(), NONE.toString()).dedup().otherV()
+ );
+ }
+ t.tree();
+ if (t.hasNext()) {
+ return (Tree)t.next();
+ } else {
+ return new Tree();
+ }
+ }
+
+ @Override
+ public List<Edge> findEdgesForVersion(Vertex start, Loader loader) {
+ final Set<String> objects = loader.getAllObjects().keySet();
+ GraphTraversal<Vertex, Edge> pipeline = this.g.V(start).union(
+ __.inE().has(CONTAINS.toString(), NONE.toString()).where(__.outV().has(AAIProperties.NODE_TYPE, P.within(objects))),
+ __.outE().has(CONTAINS.toString(), NONE.toString()).where(__.inV().has(AAIProperties.NODE_TYPE, P.within(objects)))
+ ).dedup();
+
+ return pipeline.toList();
+ }
+
+
+ @Override
+ public List<Vertex> findCousinVertices(Vertex start) {
+ GraphTraversal<Vertex, Vertex> pipeline = this.g.V(start).union(
+ __.inE().has(CONTAINS.toString(), NONE.toString()),
+ __.outE().has(CONTAINS.toString(), NONE.toString())).otherV().dedup();
+
+ return pipeline.toList();
+ }
+
+}
+
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinPipelineQueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinPipelineQueryEngine.java
new file mode 100644
index 00000000..e8acaecd
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinPipelineQueryEngine.java
@@ -0,0 +1,206 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.engines.query;/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+package org.onap.aai.serialization.engines.query;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.onap.aai.db.AAIProperties;
+import org.onap.aai.query.builder.QueryBuilder;
+import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import com.tinkerpop.blueprints.Direction;
+import com.tinkerpop.blueprints.TransactionalGraph;
+import com.tinkerpop.blueprints.Vertex;
+import com.tinkerpop.gremlin.java.GremlinPipeline;
+import com.tinkerpop.pipes.IdentityPipe;
+import com.tinkerpop.pipes.PipeFunction;
+import com.tinkerpop.pipes.branch.LoopPipe;
+
+public class GremlinPipelineQueryEngine extends QueryEngine {
+
+ public GremlinPipelineQueryEngine(TransactionalGraphEngine graphEngine) {
+ super(graphEngine);
+ }
+
+ @Override
+ public List<Vertex> executeQuery(TransactionalGraph g, QueryBuilder query) {
+ List<Vertex> results = null;
+ Vertex start = query.getStart();
+ if (start != null) {
+ results = ((GremlinPipeline)query.getQuery()).cast(Vertex.class).toList();
+ } else {
+ GremlinPipeline pipe = new GremlinPipeline(g);
+ results = process(pipe, (GremlinPipeline)query.getQuery());
+
+ }
+ return results;
+ }
+
+ @Override
+ public List<Vertex> executeParentQuery(TransactionalGraph g, QueryBuilder query) {
+ List<Vertex> results = null;
+ Vertex start = query.getStart();
+ if (start != null) {
+ results = ((GremlinPipeline)query.getParentQuery()).cast(Vertex.class).toList();
+ } else {
+ GremlinPipeline pipe = new GremlinPipeline(g);
+ results = process(pipe, (GremlinPipeline)query.getParentQuery());
+
+ }
+ return results;
+ }
+
+ @Override
+ public List<Vertex> findParents(Vertex start) {
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline(start).as("x").inE()
+ .has("isParent", true).outV().loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject());
+ return pipe.inE().has("isParent", true).count() == 1 || argument.getLoops() < 100;
+ }
+
+ }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ return true;
+ }
+
+ });
+
+ List<Vertex> results = pipe.toList();
+ results.add(0, start);
+ return results;
+ }
+
+ @Override
+ public List<Vertex> findChildren(Vertex start) {
+ Set<Vertex> seen = new HashSet<>();
+ seen.add(start);
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline(start).as("x").outE().has("isParent", true).inV()
+ .except(seen).store(seen).loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject());
+ return pipe.outE().has("isParent", true).count() >= 1 || argument.getLoops() < 100;
+ }
+
+ }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ return true;
+ }
+
+ });
+
+ List<Vertex> results = pipe.toList();
+ results.add(0, start);
+ return results;
+ }
+
+ @Override
+ public List<Vertex> findDeletable(Vertex start) {
+ Set<Vertex> seen = new HashSet<>();
+ seen.add(start);
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>(start).as("x").outE().or(
+ new GremlinPipeline(new IdentityPipe()).has("isParent", true),
+ new GremlinPipeline(new IdentityPipe()).has("hasDelTarget", true)).inV()
+ .except(seen).store(seen).loop("x", new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ GremlinPipeline<Vertex, Long> pipe = new GremlinPipeline<>(argument.getObject());
+ return pipe.outE().or(
+ new GremlinPipeline(new IdentityPipe()).has("isParent", true),
+ new GremlinPipeline(new IdentityPipe()).has("hasDelTarget", true)).count() >= 1 || argument.getLoops() < 100;
+ }
+
+ }, new PipeFunction<LoopPipe.LoopBundle<Vertex>, Boolean>() {
+
+ @Override
+ public Boolean compute(LoopPipe.LoopBundle<Vertex> argument) {
+ return true;
+ }
+
+ });
+ List<Vertex> results = pipe.toList();
+ results.add(0, start);
+
+ return results;
+ }
+
+ private List<Vertex> process(GremlinPipeline start, GremlinPipeline pipe) {
+
+
+ return start.add(pipe).cast(Vertex.class).toList();
+ }
+
+ @Override
+ public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) {
+ GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<Vertex, Vertex>(start);
+ switch (direction) {
+ case OUT:
+ pipe.out(label);
+ break;
+ case IN:
+ pipe.in(label);
+ break;
+ case BOTH:
+ pipe.both(label);
+ break;
+ default:
+ break;
+ }
+
+ pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup();
+ List<Vertex> result = pipe.toList();
+ return result;
+ }
+
+}
+*/
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinQueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinQueryEngine.java
new file mode 100644
index 00000000..ab622963
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GremlinQueryEngine.java
@@ -0,0 +1,196 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.engines.query;/*-
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+//
+//package org.onap.aai.serialization.engines.query;
+//
+//import java.util.List;
+//import java.util.regex.Matcher;
+//import java.util.regex.Pattern;
+//
+//import org.apache.commons.collections.IteratorUtils;
+//
+//import org.onap.aai.db.AAIProperties;
+//import org.onap.aai.query.builder.QueryBuilder;
+//import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+//import com.tinkerpop.blueprints.Direction;
+//import com.tinkerpop.blueprints.Graph;
+//import com.tinkerpop.blueprints.TransactionalGraph;
+//import com.tinkerpop.blueprints.Vertex;
+//import com.tinkerpop.gremlin.groovy.Gremlin;
+//import com.tinkerpop.gremlin.java.GremlinPipeline;
+//import com.tinkerpop.pipes.Pipe;
+//import com.tinkerpop.pipes.util.iterators.SingleIterator;
+//
+//public class GremlinQueryEngine extends QueryEngine {
+//
+// public GremlinQueryEngine (TransactionalGraphEngine engine) {
+// super(engine);
+//
+// }
+//
+//
+// @Override
+// public List<Vertex> executeQuery(TransactionalGraph g, QueryBuilder query) {
+// List<Vertex> result = null;
+// Vertex start = query.getStart();
+// if (start != null) {
+// result = this.executeQuery(start, (String)query.getQuery());
+// } else {
+// result = this.processGremlinQuery((String)query.getQuery());
+// }
+// return result;
+//
+// }
+//
+// @Override
+// public List<Vertex> executeParentQuery(TransactionalGraph g, QueryBuilder query) {
+//
+// List<Vertex> result = null;
+// Vertex start = query.getStart();
+// if (start != null) {
+// result = this.executeQuery(start, (String)query.getParentQuery());
+// } else {
+// result = this.processGremlinQuery((String)query.getParentQuery());
+// }
+// return result;
+// }
+//
+// private List<Vertex> executeQuery(Vertex startVertex, String query) {
+//
+// return this.processGremlinQuery(startVertex, "_()" + query);
+//
+// }
+//
+// @Override
+// public List<Vertex> findParents(Vertex start) {
+//
+// String findAllParents = ".as('x').inE.has('isParent', true).outV"
+// + ".loop('x'){it.object.inE.has('isParent',true).count()==1}{true}";
+//
+// List<Vertex> results = this.executeQuery(start, findAllParents);
+// results.add(0, start);
+// return results;
+//
+// }
+//
+// @Override
+// public List<Vertex> findChildren(Vertex start) {
+// String findAllChildren = ".as('x').outE.has('isParent', true).inV"
+// + ".loop('x'){it.object.outE.has('isParent', true).count() >= 1}{true}";
+//
+// List<Vertex> results = this.executeQuery(start, findAllChildren);
+// results.add(0, start);
+// return results;
+//
+// }
+//
+// @Override
+// public List<Vertex> findDeletable(Vertex start) {
+// String findAllChildren = ".as('x').outE.or(_().has('isParent', true), _().has('hasDelTarget', true)).inV"
+// + ".loop('x'){it.object.outE.or(_().has('isParent', true), _().has('hasDelTarget', true)).count() >= 1}{true}";
+//
+// List<Vertex> results = this.executeQuery(start, findAllChildren);
+// results.add(0, start);
+// return results;
+// }
+// private List<Vertex> processGremlinQuery(String query) {
+//
+// Pattern firstHasSet = Pattern.compile("^(\\.has\\(.*?\\))(\\.has\\(.*?\\))*(?!\\.has)");
+// Pattern p = Pattern.compile("\\.has\\('(.*?)',\\s?'(.*?)'\\)");
+// Matcher m = firstHasSet.matcher(query);
+// List<Vertex> results = null;
+// GremlinPipeline<Graph, Vertex> pipe = new GremlinPipeline<>(dbEngine.getGraph());
+// if (m.find()) {
+// String hasSet = m.group();
+// query = query.replace(m.group(0), "");
+// m = p.matcher(hasSet);
+// pipe.V();
+// while (m.find()) {
+// pipe.has(m.group(1), m.group(2));
+// }
+// results = processGremlinQuery(pipe.toList(), "_()" + query);
+// }
+//
+// return results;
+//
+// }
+// private List<Vertex> processGremlinQuery(Vertex startVertex, String query) {
+//
+// Pipe pipe = Gremlin.compile(query);
+// pipe.setStarts(new SingleIterator<Vertex>(startVertex));
+//
+// return (List<Vertex>)IteratorUtils.toList(pipe.iterator());
+// }
+// private List<Vertex> processGremlinQuery(List<Vertex> list, String query) {
+//
+// Pipe pipe = Gremlin.compile(query);
+//
+// pipe.setStarts(list);
+//
+// return (List<Vertex>)IteratorUtils.toList(pipe.iterator());
+// }
+//
+//
+// @Override
+// public List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType) {
+// String findRelatedVertices = "_()";
+// switch (direction) {
+// case OUT:
+// findRelatedVertices += ".out('" + label + "')";
+// break;
+// case IN:
+// findRelatedVertices += ".in('" + label + "')";
+// break;
+// case BOTH:
+// findRelatedVertices += ".both('" + label + "')";
+// break;
+// default:
+// break;
+// }
+// findRelatedVertices += ".has('" + AAIProperties.NODE_TYPE + "', '" + nodeType + "').dedup()";
+// List<Vertex> results = this.executeQuery(start, findRelatedVertices);
+// results.add(0, start);
+// return results;
+// }
+//
+//}
+//
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java
new file mode 100644
index 00000000..01f11b17
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java
@@ -0,0 +1,94 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.engines.query;
+
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Element;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.introspection.Loader;
+
+import java.util.List;
+
+public abstract class QueryEngine {
+
+ final protected GraphTraversalSource g;
+
+ /**
+ * Instantiates a new query engine.
+ *
+ * @param graphEngine the graph engine
+ */
+ public QueryEngine (GraphTraversalSource g) {
+ this.g = g;
+ }
+
+ /**
+ * Find parents.
+ *
+ * @param start the start
+ * @return the list
+ */
+ public abstract List<Vertex> findParents(Vertex start);
+
+ /**
+ * Find children.
+ *
+ * @param start the start
+ * @return the list
+ */
+ public abstract List<Vertex> findAllChildren(Vertex start);
+
+ public abstract List<Vertex> findChildrenOfType(Vertex start, String type);
+
+ public abstract List<Vertex> findChildren(Vertex start);
+ /**
+ * Find deletable.
+ *
+ * @param start the start
+ * @return the list
+ */
+ public abstract List<Vertex> findDeletable(Vertex start);
+
+ public Tree<Element> findSubGraph(Vertex start) {
+ return findSubGraph(start, AAIProperties.MAXIMUM_DEPTH, false);
+ }
+ public abstract Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly);
+ /**
+ * Find related vertices.
+ *
+ * @param start the start
+ * @param direction the direction
+ * @param label the label
+ * @param nodeType the node type
+ * @return the list
+ */
+ public abstract List<Vertex> findRelatedVertices(Vertex start, Direction direction, String label, String nodeType);
+
+ public abstract List<Edge> findEdgesForVersion(Vertex start, Loader loader);
+
+ public abstract List<Vertex> findCousinVertices(Vertex start);
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java
new file mode 100644
index 00000000..f101f890
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java
@@ -0,0 +1,43 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import com.google.gson.JsonObject;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+
+public class Console implements FormatMapper {
+
+ @Override
+ public JsonObject formatObject(Object v) throws AAIFormatVertexException {
+
+ JsonObject json = new JsonObject();
+ json.addProperty("result", v.toString());
+
+ return json;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 100;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java
new file mode 100644
index 00000000..2904cce6
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java
@@ -0,0 +1,31 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+public enum Format {
+ graphson,
+ pathed, id, resource,
+ simple,
+ resource_and_url,
+ console,
+ raw
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java
new file mode 100644
index 00000000..b19e0c3e
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java
@@ -0,0 +1,97 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.queryformats.exceptions.QueryParamInjectionException;
+import org.onap.aai.serialization.queryformats.utils.QueryParamInjector;
+import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
+
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+
+public class FormatFactory {
+
+ private final Loader loader;
+ private final DBSerializer serializer;
+ private final UrlBuilder urlBuilder;
+ private final QueryParamInjector injector;
+ public FormatFactory (Loader loader, DBSerializer serializer) throws AAIException {
+ this.loader = loader;
+ this.serializer = serializer;
+ this.urlBuilder = new UrlBuilder(loader.getVersion(), serializer);
+ this.injector = QueryParamInjector.getInstance();
+ }
+
+ public Formatter get(Format format) throws AAIException {
+ return get(format, new MultivaluedHashMap<String, String>());
+ }
+
+ public Formatter get(Format format, MultivaluedMap<String, String> params) throws AAIException {
+
+ Formatter formattter = null;
+
+ switch (format) {
+ case graphson :
+ formattter = new Formatter(inject(new GraphSON(), params));
+ break;
+ case pathed :
+ formattter = new Formatter(inject(new PathedURL(loader, urlBuilder), params));
+ break;
+ case id :
+ formattter = new Formatter(inject(new IdURL(loader, urlBuilder), params));
+ break;
+ case resource :
+ formattter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder), params).build());
+ break;
+ case resource_and_url :
+ formattter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder).includeUrl(), params).build());
+ break;
+ case raw :
+ formattter = new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder), params).build());
+ break;
+ case simple :
+ formattter = new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder).depth(0).modelDriven(), params).build());
+ break;
+ case console :
+ formattter = new Formatter(inject(new Console(), params));
+ break;
+ default :
+ break;
+
+ }
+
+ return formattter;
+ }
+
+ private <T> T inject (T obj, MultivaluedMap<String, String> params) throws QueryParamInjectionException {
+
+ injector.injectParams(obj, params);
+ return obj;
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java
new file mode 100644
index 00000000..fb822dd9
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java
@@ -0,0 +1,32 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import com.google.gson.JsonObject;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+
+public interface FormatMapper {
+
+ public JsonObject formatObject(Object v) throws AAIFormatVertexException;
+
+ public int parallelThreshold();
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java
new file mode 100644
index 00000000..50042b76
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java
@@ -0,0 +1,80 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class Formatter {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Formatter.class);
+
+ protected JsonParser parser = new JsonParser();
+ protected final FormatMapper format;
+ public Formatter (FormatMapper format) {
+ this.format = format;
+ }
+
+ public JsonObject output(List<Object> vertices) {
+ Stream<Object> stream = null;
+ JsonObject result = new JsonObject();
+ JsonArray body = new JsonArray();
+ if (vertices.size() >= format.parallelThreshold()) {
+ stream = vertices.parallelStream();
+ } else {
+ stream = vertices.stream();
+ }
+ final boolean isParallel = stream.isParallel();
+ stream.map(v -> {
+ try {
+ return Optional.<JsonObject>of(format.formatObject(v));
+ } catch (AAIFormatVertexException e) {
+ LOGGER.warn("Failed to format vertex, returning a partial list", e);
+ }
+
+ return Optional.<JsonObject>empty();
+ }).forEach(obj -> {
+ if (obj.isPresent()) {
+ if (isParallel) {
+ synchronized (body) {
+ body.add(obj.get());
+ }
+ } else {
+ body.add(obj.get());
+ }
+ }
+ });
+
+ result.add("results", body);
+
+ return result.getAsJsonObject();
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java
new file mode 100644
index 00000000..00aa781c
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java
@@ -0,0 +1,63 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.thinkaurelius.titan.graphdb.tinkerpop.TitanIoRegistry;
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class GraphSON implements FormatMapper {
+
+ private final GraphSONMapper mapper = GraphSONMapper.build().addRegistry(TitanIoRegistry.INSTANCE).create();
+ private final GraphSONWriter writer = GraphSONWriter.build().mapper(mapper).create();
+ protected JsonParser parser = new JsonParser();
+
+ @Override
+ public JsonObject formatObject(Object v) {
+ OutputStream os = new ByteArrayOutputStream();
+ String result = "";
+ try {
+ writer.writeVertex(os, (Vertex)v, Direction.BOTH);
+
+ result = os.toString();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ return parser.parse(result).getAsJsonObject();
+
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 50;
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java
new file mode 100644
index 00000000..320cd616
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java
@@ -0,0 +1,71 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
+
+public class IdURL implements FormatMapper {
+
+ private final UrlBuilder urlBuilder;
+ private final JsonParser parser;
+ private final Loader loader;
+
+ public IdURL (Loader loader, UrlBuilder urlBuilder) throws AAIException {
+ this.urlBuilder = urlBuilder;
+ this.parser = new JsonParser();
+ this.loader = loader;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 2500;
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ try {
+ final Introspector searchResult = this.loader.introspectorFromName("result-data");
+
+ searchResult.setValue("resource-type", v.value(AAIProperties.NODE_TYPE));
+ searchResult.setValue("resource-link", this.urlBuilder.id(v));
+
+ final String json = searchResult.marshal(false);
+
+ return parser.parse(json).getAsJsonObject();
+
+ } catch (AAIUnknownObjectException e) {
+ throw new RuntimeException("Fatal error - result-data object does not exist!");
+ }
+
+
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java
new file mode 100644
index 00000000..8b9d5058
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java
@@ -0,0 +1,70 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
+
+public final class PathedURL implements FormatMapper {
+
+ private final UrlBuilder urlBuilder;
+ private final JsonParser parser;
+ private final Loader loader;
+
+ public PathedURL (Loader loader, UrlBuilder urlBuilder) throws AAIException {
+ this.urlBuilder = urlBuilder;
+ this.parser = new JsonParser();
+ this.loader = loader;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 20;
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ try {
+ final Introspector searchResult = this.loader.introspectorFromName("result-data");
+
+ searchResult.setValue("resource-type", v.value(AAIProperties.NODE_TYPE));
+
+ searchResult.setValue("resource-link", this.urlBuilder.pathed(v));
+ final String json = searchResult.marshal(false);
+ return this.parser.parse(json).getAsJsonObject();
+
+ } catch (AAIUnknownObjectException e) {
+ throw new RuntimeException("Fatal error - result-data does not exist!", e);
+ }
+
+ }
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java
new file mode 100644
index 00000000..7aaf3035
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java
@@ -0,0 +1,190 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.onap.aai.serialization.queryformats.params.Depth;
+import org.onap.aai.serialization.queryformats.params.NodesOnly;
+import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+
+public class RawFormat implements FormatMapper {
+ protected JsonParser parser = new JsonParser();
+ protected final DBSerializer serializer;
+ protected final Loader loader;
+ protected final UrlBuilder urlBuilder;
+ protected final int depth;
+ protected final boolean nodesOnly;
+ protected RawFormat(Builder builder) {
+ this.urlBuilder = builder.getUrlBuilder();
+ this.loader = builder.getLoader();
+ this.serializer = builder.getSerializer();
+ this.depth = builder.getDepth();
+ this.nodesOnly = builder.isNodesOnly();
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ JsonObject json = new JsonObject();
+ json.addProperty("id", v.id().toString());
+ json.addProperty("node-type", v.<String>value(AAIProperties.NODE_TYPE));
+ json.addProperty("url", this.urlBuilder.pathed(v));
+ json.add("properties", this.createPropertiesObject(v));
+ if (!nodesOnly) {
+ json.add("related-to", this.createRelationshipObject(v));
+ }
+ return json;
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 100;
+ }
+
+
+ public JsonObject createPropertiesObject(Vertex v) throws AAIFormatVertexException {
+ JsonObject json = new JsonObject();
+ Iterator<VertexProperty<Object>> iter = v.properties();
+
+ while (iter.hasNext()) {
+ VertexProperty<Object> prop = iter.next();
+ if (prop.value() instanceof String) {
+ json.addProperty(prop.key(), (String)prop.value());
+ } else if (prop.value() instanceof Boolean) {
+ json.addProperty(prop.key(), (Boolean)prop.value());
+ } else if (prop.value() instanceof Number) {
+ json.addProperty(prop.key(), (Number)prop.value());
+ } else if (prop.value() instanceof List) {
+ Gson gson = new Gson();
+ String list = gson.toJson(prop.value());
+
+ json.addProperty(prop.key(), list);
+ } else {
+ //throw exception?
+ return null;
+ }
+ }
+
+ return json;
+ }
+ protected JsonArray createRelationshipObject(Vertex v) throws AAIFormatVertexException {
+ JsonArray jarray = new JsonArray();
+ Iterator<Vertex> iter = v.vertices(Direction.BOTH);
+
+ while (iter.hasNext()) {
+ Vertex related = iter.next();
+
+ JsonObject json = new JsonObject();
+ json.addProperty("id", related.id().toString());
+ json.addProperty("node-type", related.<String>value(AAIProperties.NODE_TYPE));
+ json.addProperty("url", this.urlBuilder.pathed(related));
+ jarray.add(json);
+ }
+
+ return jarray;
+ }
+
+ public static class Builder implements NodesOnly<Builder>, Depth<Builder> {
+
+ protected final Loader loader;
+ protected final DBSerializer serializer;
+ protected final UrlBuilder urlBuilder;
+ protected boolean includeUrl = false;
+ protected boolean nodesOnly = false;
+ protected int depth = 1;
+ protected boolean modelDriven = false;
+ public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) {
+ this.loader = loader;
+ this.serializer = serializer;
+ this.urlBuilder = urlBuilder;
+ }
+
+ protected Loader getLoader() {
+ return this.loader;
+ }
+
+ protected DBSerializer getSerializer() {
+ return this.serializer;
+ }
+
+ protected UrlBuilder getUrlBuilder() {
+ return this.urlBuilder;
+ }
+
+ public Builder includeUrl() {
+ this.includeUrl = true;
+ return this;
+ }
+
+ public Builder nodesOnly(Boolean nodesOnly) {
+ this.nodesOnly = nodesOnly;
+ return this;
+ }
+ public boolean isNodesOnly() {
+ return this.nodesOnly;
+ }
+
+ public Builder depth(Integer depth) {
+ this.depth = depth;
+ return this;
+ }
+
+ public int getDepth() {
+ return this.depth;
+ }
+
+ public boolean isIncludeUrl() {
+ return this.includeUrl;
+ }
+
+ public Builder modelDriven() {
+ this.modelDriven = true;
+ return this;
+ }
+
+ public boolean getModelDriven() {
+ return this.modelDriven;
+ }
+ public RawFormat build() {
+ if (modelDriven) {
+ return new SimpleFormat(this);
+ } else {
+ return new RawFormat(this);
+ }
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java
new file mode 100644
index 00000000..649971be
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java
@@ -0,0 +1,163 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.Loader;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.onap.aai.serialization.queryformats.params.Depth;
+import org.onap.aai.serialization.queryformats.params.NodesOnly;
+import org.onap.aai.serialization.queryformats.utils.UrlBuilder;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class Resource implements FormatMapper {
+
+ private final Loader loader;
+ private final DBSerializer serializer;
+ private final JsonParser parser;
+ private final UrlBuilder urlBuilder;
+ private final boolean includeUrl;
+ private final boolean nodesOnly;
+ private final int depth;
+ private Resource (Builder builder) {
+ this.parser = new JsonParser();
+ this.loader = builder.getLoader();
+ this.serializer = builder.getSerializer();
+ this.urlBuilder = builder.getUrlBuilder();
+ this.includeUrl = builder.isIncludeUrl();
+ this.nodesOnly = builder.isNodesOnly();
+ this.depth = builder.getDepth();
+ }
+
+ @Override
+ public JsonObject formatObject(Object input) throws AAIFormatVertexException {
+ Vertex v = (Vertex)input;
+ JsonObject json = new JsonObject();
+
+ if (this.includeUrl) {
+ json.addProperty("url", this.urlBuilder.pathed(v));
+ }
+ json.add(v.<String>property(AAIProperties.NODE_TYPE)
+ .orElse(null), this.vertexToJsonObject(v));
+
+ return json;
+ }
+
+ protected JsonObject vertexToJsonObject(Vertex v) throws AAIFormatVertexException {
+ try {
+ final Introspector obj = getLoader().introspectorFromName(
+ v.<String>property(AAIProperties.NODE_TYPE)
+ .orElse(null)
+ );
+
+ final List<Vertex> wrapper = new ArrayList<>();
+
+ wrapper.add(v);
+
+ try {
+ getSerializer().dbToObject(wrapper, obj, this.depth, this.nodesOnly, "false");
+ } catch (AAIException | UnsupportedEncodingException e) {
+ throw new AAIFormatVertexException("Failed to format vertex - error while serializing: " + e.getMessage(), e);
+ }
+
+ final String json = obj.marshal(false);
+
+ return getParser().parse(json).getAsJsonObject();
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIFormatVertexException("Failed to format vertex - unknown object", e);
+ }
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 20;
+ }
+
+ private Loader getLoader() { return loader; }
+ private DBSerializer getSerializer() { return serializer; }
+ private JsonParser getParser() { return parser; }
+
+ public static class Builder implements NodesOnly<Builder>, Depth<Builder> {
+
+ private final Loader loader;
+ private final DBSerializer serializer;
+ private final UrlBuilder urlBuilder;
+ private boolean includeUrl = false;
+ private boolean nodesOnly = false;
+ private int depth = 1;
+ public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) {
+ this.loader = loader;
+ this.serializer = serializer;
+ this.urlBuilder = urlBuilder;
+ }
+
+ protected Loader getLoader() {
+ return this.loader;
+ }
+
+ protected DBSerializer getSerializer() {
+ return this.serializer;
+ }
+
+ protected UrlBuilder getUrlBuilder() {
+ return this.urlBuilder;
+ }
+
+ public Builder includeUrl() {
+ this.includeUrl = true;
+ return this;
+ }
+
+ public Builder nodesOnly(Boolean nodesOnly) {
+ this.nodesOnly = nodesOnly;
+ return this;
+ }
+ public boolean isNodesOnly() {
+ return this.nodesOnly;
+ }
+ public Builder depth(Integer depth) {
+ this.depth = depth;
+ return this;
+ }
+ public int getDepth() {
+ return this.depth;
+ }
+ public boolean isIncludeUrl() {
+ return this.includeUrl;
+ }
+
+ public Resource build() {
+ return new Resource(this);
+ }
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/SimpleFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/SimpleFormat.java
new file mode 100644
index 00000000..ba49e3a3
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/SimpleFormat.java
@@ -0,0 +1,76 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.db.props.AAIProperties;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Introspector;
+import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+
+import com.google.gson.JsonObject;
+
+public class SimpleFormat extends RawFormat {
+
+
+ protected SimpleFormat(Builder builder) {
+ super(builder);
+
+ }
+
+ @Override
+ public int parallelThreshold() {
+ return 20;
+ }
+
+ @Override
+ public JsonObject createPropertiesObject(Vertex v) throws AAIFormatVertexException {
+ try {
+ final Introspector obj = loader.introspectorFromName(
+ v.<String>property(AAIProperties.NODE_TYPE)
+ .orElse(null)
+ );
+
+ final List<Vertex> wrapper = new ArrayList<>();
+
+ wrapper.add(v);
+
+ try {
+ serializer.dbToObject(wrapper, obj, this.depth, true, "false");
+ } catch (AAIException | UnsupportedEncodingException e) {
+ throw new AAIFormatVertexException("Failed to format vertex - error while serializing: " + e.getMessage(), e);
+ }
+
+ final String json = obj.marshal(false);
+ return parser.parse(json).getAsJsonObject();
+ } catch (AAIUnknownObjectException e) {
+ throw new AAIFormatVertexException("Failed to format vertex - unknown object", e);
+ }
+
+
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/SubGraphStyle.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/SubGraphStyle.java
new file mode 100644
index 00000000..6a8acd2f
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/SubGraphStyle.java
@@ -0,0 +1,28 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats;
+
+public enum SubGraphStyle {
+ star,
+ prune,
+ no_op
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java
new file mode 100644
index 00000000..98b90050
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatVertexException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.exceptions;
+
+public class AAIFormatVertexException extends Exception {
+
+ private static final long serialVersionUID = -5814240841844624097L;
+
+ public AAIFormatVertexException() {}
+
+ public AAIFormatVertexException(String message) {
+ super(message);
+ }
+
+ public AAIFormatVertexException(Throwable cause) {
+ super(cause);
+ }
+
+ public AAIFormatVertexException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/QueryParamInjectionException.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/QueryParamInjectionException.java
new file mode 100644
index 00000000..313b8942
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/QueryParamInjectionException.java
@@ -0,0 +1,41 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.exceptions;
+
+import org.onap.aai.exceptions.AAIException;
+
+public class QueryParamInjectionException extends AAIException {
+
+ private static final long serialVersionUID = -5575661036426538012L;
+
+ public QueryParamInjectionException(String message) {
+ super("AAI_4017", message);
+ }
+
+ public QueryParamInjectionException(Throwable cause) {
+ super("AAI_4017",cause);
+ }
+
+ public QueryParamInjectionException(String message, Throwable cause) {
+ super("AAI_4017", cause, message);
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Depth.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Depth.java
new file mode 100644
index 00000000..e98f0667
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Depth.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.params;
+
+@Inject(name = "depth")
+public interface Depth<T> {
+
+ @Setter
+ public T depth(Integer depth);
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Inject.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Inject.java
new file mode 100644
index 00000000..18d85545
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Inject.java
@@ -0,0 +1,35 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.params;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Inject {
+
+ /**
+ * The way the query parameter appears in the URI
+ * @return
+ */
+ String name();
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/NodesOnly.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/NodesOnly.java
new file mode 100644
index 00000000..1429d552
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/NodesOnly.java
@@ -0,0 +1,29 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.params;
+
+@Inject(name = "nodesOnly")
+public interface NodesOnly<T> {
+
+ @Setter
+ public T nodesOnly(Boolean nodesOnly);
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Setter.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Setter.java
new file mode 100644
index 00000000..e95de0db
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/Setter.java
@@ -0,0 +1,37 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.params;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+/**
+ * Marks what method in the object should be used for setting the value
+ * of the query parameter
+ */
+public @interface Setter {
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java
new file mode 100644
index 00000000..29fb56df
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java
@@ -0,0 +1,85 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.utils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.onap.aai.serialization.queryformats.exceptions.QueryParamInjectionException;
+import org.onap.aai.serialization.queryformats.params.Inject;
+import org.onap.aai.serialization.queryformats.params.Setter;
+import org.reflections.Reflections;
+
+public class QueryParamInjector {
+
+ private final Set<Class<?>> results;
+
+
+ private QueryParamInjector () {
+ Reflections reflections = new Reflections("org.onap.aai.serialization.queryformats.params");
+ results = reflections.getTypesAnnotatedWith(Inject.class);
+ }
+
+ private static class Helper {
+ private static final QueryParamInjector INSTANCE = new QueryParamInjector();
+ }
+
+ public static QueryParamInjector getInstance() {
+ return Helper.INSTANCE;
+ }
+
+ public <T> T injectParams(T obj, MultivaluedMap<String, String> params) throws QueryParamInjectionException{
+ try {
+ for (Class<?> item : results) {
+ if (item.isAssignableFrom(obj.getClass())) {
+ String name = item.getAnnotation(Inject.class).name();
+
+ if (params.containsKey(name)) {
+ String value = params.getFirst(name);
+
+ for (Method method : item.getMethods()) {
+ if (method.isAnnotationPresent(Setter.class)) {
+ Class<?>[] args = method.getParameterTypes();
+ if (args.length == 1) {
+ Object o = args[0].getConstructor(String.class).newInstance(value);
+ method.invoke(obj, o);
+ } else {
+ method.invoke(obj);
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException | NoSuchMethodException
+ | SecurityException e) {
+ throw new QueryParamInjectionException("issue with query params", e);
+ }
+
+
+ return obj;
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/UrlBuilder.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/UrlBuilder.java
new file mode 100644
index 00000000..8387285d
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/UrlBuilder.java
@@ -0,0 +1,92 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.queryformats.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.introspection.Version;
+import org.onap.aai.serialization.db.DBSerializer;
+import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException;
+import org.onap.aai.util.AAIApiServerURLBase;
+import org.onap.aai.util.AAIConstants;
+import org.onap.aai.workarounds.LegacyURITransformer;
+
+public class UrlBuilder {
+
+ private final DBSerializer serializer;
+ private final Version version;
+ private final String serverBase;
+
+ public UrlBuilder (Version version, DBSerializer serializer) throws AAIException {
+ this.serializer = serializer;
+ this.version = version;
+ this.serverBase = this.getServerBase(version);
+ }
+
+ public UrlBuilder (Version version, DBSerializer serializer, String serverBase) {
+ this.serializer = serializer;
+ this.version = version;
+ this.serverBase = serverBase;
+ }
+
+ public String pathed(Vertex v) throws AAIFormatVertexException {
+
+ try {
+ final StringBuilder result = new StringBuilder();
+ final URI uri = this.serializer.getURIForVertex(v);
+
+ if (this.version.compareTo(Version.v11) >= 0) {
+ result.append(AAIConstants.AAI_APP_ROOT);
+ } else {
+ result.append(this.serverBase);
+ }
+ result.append(this.version);
+ result.append(uri);
+
+ return result.toString();
+ } catch (UnsupportedEncodingException | IllegalArgumentException | SecurityException e) {
+ throw new AAIFormatVertexException(e);
+ }
+ }
+
+ public String id(Vertex v) {
+ final StringBuilder result = new StringBuilder();
+
+ result.append("/resources/id/" + v.id());
+ result.insert(0, this.version);
+ if (this.version.compareTo(Version.v11) >= 0) {
+ result.insert(0, AAIConstants.AAI_APP_ROOT);
+ } else {
+ result.insert(0, this.serverBase);
+ }
+
+ return result.toString();
+ }
+
+ protected String getServerBase(Version v) throws AAIException {
+ return AAIApiServerURLBase.get(v);
+ }
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedEdge.java b/aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedEdge.java
new file mode 100644
index 00000000..82aa7443
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedEdge.java
@@ -0,0 +1,81 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.tinkerpop;
+
+import org.apache.tinkerpop.gremlin.structure.Direction;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedEdge;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+
+import java.util.Iterator;
+
+
+/**
+ * Represents a {@link Edge} that is disconnected from a {@link Graph} however,
+ * traversals are supported as they are backed by a Tree with saturated {@link Vertex} and {@link Edge} objects.
+ * These objects are not mutable and can only be used to read information out.
+ *
+ */
+public class TreeBackedEdge extends DetachedEdge implements Edge {
+
+ private static final long serialVersionUID = 5419650145562077538L;
+ private TreeBackedVertex inVertex;
+ private TreeBackedVertex outVertex;
+ public TreeBackedEdge(Edge edge, TreeBackedVertex inVertex, TreeBackedVertex outVertex) {
+ super(edge, true);
+ this.inVertex = inVertex;
+ this.outVertex = outVertex;
+ }
+
+ @Override
+ public Vertex inVertex() {
+ return this.inVertex;
+ }
+
+ @Override
+ public Vertex outVertex() {
+ return this.outVertex;
+ }
+
+ @Override
+ public Iterator<Vertex> bothVertices() {
+ return this.vertices(Direction.BOTH);
+ }
+
+ @Override
+ public Iterator<Vertex> vertices(Direction direction) {
+ switch (direction) {
+ case OUT:
+ return IteratorUtils.of(this.outVertex);
+ case IN:
+ return IteratorUtils.of(this.inVertex);
+ default:
+ return IteratorUtils.of(this.outVertex, this.inVertex);
+ }
+ }
+
+
+
+
+}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedVertex.java b/aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedVertex.java
new file mode 100644
index 00000000..e953dc2d
--- /dev/null
+++ b/aai-core/src/main/java/org/onap/aai/serialization/tinkerpop/TreeBackedVertex.java
@@ -0,0 +1,163 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ * ECOMP is a trademark and service mark of AT&T Intellectual Property.
+ */
+package org.onap.aai.serialization.tinkerpop;
+
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.*;
+import org.apache.tinkerpop.gremlin.structure.util.detached.DetachedVertex;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Represents a {@link Vertex} that is disconnected from a {@link Graph} however,
+ * traversals are supported as they are backed by a Tree with saturated {@link Vertex} and {@link Edge} objects.
+ * These objects are not mutable and can only be used to read information out.
+ *
+ */
+
+public class TreeBackedVertex extends DetachedVertex implements Vertex {
+
+ private static final long serialVersionUID = -976854460992756953L;
+ private final Tree<Element> tree;
+ private final Vertex self;
+ public TreeBackedVertex (Vertex v, Tree<Element> tree) {
+ super(v, true);
+ this.self = v;
+ this.tree = tree;
+ }
+
+ @Override
+ public Iterator<Edge> edges(final Direction direction, final String... edgeLabels) {
+ final List<Element> edges = tree.getObjectsAtDepth(2);
+ final List<Tree<Element>> trees = tree.getTreesAtDepth(2);
+ final List<Tree<Element>> vTrees = tree.getTreesAtDepth(3);
+ return edges.stream().map( ele -> (Edge)ele).filter(e -> {
+ if (Direction.IN.equals(direction)) {
+ return e.inVertex().equals(self);
+ } else if (Direction.OUT.equals(direction)) {
+ return e.outVertex().equals(self);
+ } else {
+ return true;
+ }
+ }).filter(e -> {
+ boolean result = false;
+ if (edgeLabels.length == 0) {
+ return true;
+ }
+ for (String label : edgeLabels) {
+ if (label.equals(e.label())) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }).map(e -> {
+ Tree<Element> eTree = new Tree<>();
+ for (Tree<Element> tree : trees) {
+ if (tree.keySet().contains(e)) {
+ eTree = tree;
+ break;
+ }
+ }
+ TreeBackedVertex in = null;
+ TreeBackedVertex out = null;
+ if (e.inVertex().equals(self)) {
+ in = this;
+ out = this.createForVertex(e.outVertex(), vTrees);
+ } else if (e.outVertex().equals(self)) {
+ out = this;
+ in = this.createForVertex(e.inVertex(), vTrees);
+ }
+ return (Edge)new TreeBackedEdge(e, in, out);
+ }).iterator();
+
+ }
+
+ private TreeBackedVertex createForVertex(Vertex v, List<Tree<Element>> trees) {
+ Tree<Element> vTree = new Tree<>();
+ for (Tree<Element> tree : trees) {
+ if (tree.keySet().contains(v)) {
+ vTree = tree;
+ break;
+ }
+ }
+
+ return new TreeBackedVertex((Vertex)vTree.keySet().iterator().next(), vTree);
+ }
+ @Override
+ public Iterator<Vertex> vertices(final Direction direction, final String... labels) {
+ final List<Tree<Element>> vertexElements = tree.getTreesAtDepth(3);
+ final List<Element> edgeElements = tree.getObjectsAtDepth(2);
+ return edgeElements.stream().map( ele -> (Edge)ele).filter(e -> {
+ boolean result = false;
+ if (labels.length == 0) {
+ return true;
+ }
+ for (String label : labels) {
+ if (label.equals(e.label())) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }).filter(e -> {
+ if (Direction.IN.equals(direction) && e.inVertex().equals(self)) {
+ return true;
+ } else if (Direction.OUT.equals(direction) && e.outVertex().equals(self)) {
+ return true;
+ } else if (Direction.BOTH.equals(direction)){
+ return true;
+ } else {
+ return false;
+ }
+ }).map(e -> {
+ final List<Vertex> list;
+ if (Direction.IN.equals(direction)) {
+ list = Collections.singletonList(e.outVertex());
+ } else if (Direction.OUT.equals(direction)){
+ list = Collections.singletonList(e.inVertex());
+ } else {
+ list = new ArrayList<>();
+ Iterator<Vertex> itr = e.bothVertices();
+ while (itr.hasNext()) {
+ list.add(itr.next());
+ }
+ }
+ return list;
+
+ }).flatMap(list -> list.stream()).map(v -> {
+ Tree<Element> vTree = new Tree<Element>();
+ for (Tree<Element> tree : vertexElements) {
+ if (tree.keySet().contains(v)) {
+ vTree = tree;
+ break;
+ }
+ }
+
+ return (Vertex)new TreeBackedVertex(v, vTree);
+ }).iterator();
+ }
+
+}