summaryrefslogtreecommitdiffstats
path: root/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java
diff options
context:
space:
mode:
Diffstat (limited to 'aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java')
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java3736
1 files changed, 1952 insertions, 1784 deletions
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
index 7a2c447e..9d107b1f 100644
--- 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
@@ -23,18 +23,21 @@ 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 org.janusgraph.core.SchemaViolationException;
+import com.google.common.collect.Multimap;
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.janusgraph.core.SchemaViolationException;
import org.javatuples.Triplet;
+import org.onap.aai.concurrent.AaiCallable;
+import org.onap.aai.config.SpringContextAware;
import org.onap.aai.db.props.AAIProperties;
import org.onap.aai.edges.EdgeIngestor;
import org.onap.aai.edges.EdgeRule;
import org.onap.aai.edges.EdgeRuleQuery;
+import org.onap.aai.edges.TypeAlphabetizer;
import org.onap.aai.edges.enums.AAIDirection;
import org.onap.aai.edges.enums.EdgeField;
import org.onap.aai.edges.enums.EdgeProperty;
@@ -57,6 +60,7 @@ import org.onap.aai.schema.enums.PropertyMetadata;
import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.serialization.engines.query.QueryEngine;
import org.onap.aai.serialization.tinkerpop.TreeBackedVertex;
import org.onap.aai.setup.SchemaVersion;
import org.onap.aai.setup.SchemaVersions;
@@ -64,8 +68,6 @@ import org.onap.aai.util.AAIConfig;
import org.onap.aai.util.AAIConstants;
import org.onap.aai.workarounds.NamingExceptions;
import org.springframework.context.ApplicationContext;
-import org.onap.aai.concurrent.AaiCallable;
-import org.onap.aai.config.SpringContextAware;
import javax.ws.rs.core.UriBuilder;
import java.io.UnsupportedEncodingException;
@@ -78,1790 +80,1956 @@ import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
+import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.onap.aai.serialization.engines.query.QueryEngine;
+import java.util.stream.Collectors;
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 SchemaVersion version;
- private final Loader latestLoader;
- private EdgeSerializer edgeSer;
- private EdgeIngestor edgeRules;
- private final Loader loader;
- private final String baseURL;
- private double dbTimeMsecs = 0;
- private long currentTimeMillis;
-
- private SchemaVersions schemaVersions;
- /**
- * Instantiates a new DB serializer.
- *
- * @param version the version
- * @param engine the engine
- * @param introspectionType the introspection type
- * @param sourceOfTruth the source of truth
- * @throws AAIException
- */
- public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
- this.engine = engine;
- this.sourceOfTruth = sourceOfTruth;
- this.introspectionType = introspectionType;
- this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
- SchemaVersion LATEST = schemaVersions.getDefaultVersion();
- this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST);
- this.version = version;
- this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version);
- this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
- this.currentTimeMillis = System.currentTimeMillis();
- initBeans();
- }
-
- private void initBeans() {
- //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
- ApplicationContext ctx = SpringContextAware.getApplicationContext();
- EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
- setEdgeIngestor(ei);
- EdgeSerializer es = ctx.getBean(EdgeSerializer.class);
- setEdgeSerializer(es);
- }
-
- private void backupESInit() {
- setEdgeSerializer(new EdgeSerializer(this.edgeRules));
- }
-
- public void setEdgeSerializer(EdgeSerializer edgeSer) {
- this.edgeSer = edgeSer;
- }
-
- public EdgeSerializer getEdgeSeriailizer() {
- return this.edgeSer;
- }
-
- public void setEdgeIngestor(EdgeIngestor ei) {
- this.edgeRules = ei;
- }
-
- public EdgeIngestor getEdgeIngestor(){
- return this.edgeRules;
- }
-
- /**
- * Touch standard vertex properties.
- *
- * @param v the v
- * @param isNewVertex the is new vertex
- */
- public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
- String timeNowInSec = Long.toString(currentTimeMillis);
-
- if (isNewVertex) {
- v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
- v.property(AAIProperties.CREATED_TS, timeNowInSec);
- v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
- }
- 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;
- try {
- StopWatch.conditionalStart();
- v = this.engine.tx().addVertex();
- touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
- }
- finally {
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
- 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 {
- StopWatch.conditionalStart();
- 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 {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
- }
- } else {
- serializeSingleVertex(v, obj, requestContext);
- }
-
- } catch (SchemaViolationException e) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_6117", e);
- }
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
-
- public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
- StopWatch.conditionalStart();
- try {
- boolean isTopLevel = obj.isTopLevel();
- if (isTopLevel) {
- addUriIfNeeded(v, obj.getURI());
- }
-
- processObject(obj, v, requestContext);
- if (!isTopLevel) {
- URI uri = this.getURIForVertex(v);
- URIParser parser = new URIParser(this.loader, uri);
- if (parser.validate()) {
- addUriIfNeeded(v, uri.toString());
- }
- }
- } catch (SchemaViolationException e) {
- throw new AAIException("AAI_6117", e);
- }
- finally {
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
- }
-
- private void addUriIfNeeded(Vertex v, String uri) {
- VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
- if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) {
- v.property(AAIProperties.AAI_URI, uri);
- }
- }
-
- /**
- * 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<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
- List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
-
- for (Object relationship : relationships) {
- Edge e = null;
- Vertex cousinVertex = null;
- String label = null;
- Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
- QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
-
- if (wrappedRel.hasProperty("relationship-label")) {
- label = wrappedRel.getValue("relationship-label");
- }
-
- 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) {
- String vType = (String)v.property(AAIProperties.NODE_TYPE).value();
- String cousinType = (String)cousinVertex.property(AAIProperties.NODE_TYPE).value();
- EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label);
-
-
- if (!edgeRules.hasRule(baseQ.build())) {
- 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() + (label != null ? (" with label " + label):"") +".");
- } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
- throw new AAIException("AAI_6145");
- }
-
- e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
-
- if (e == null) {
- addEdges.add(new Triplet<>(v, cousinVertex, label));
- } else {
- existingEdges.remove(e);
- }
- }
- }
-
- for (Edge edge : existingEdges) {
- edge.remove();
- }
- for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
- try {
- edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2());
- } 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<Vertex> 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();
- addUriIfNeeded(child, parentUri + uri);
- }
- processObject(obj, child, requestContext);
-
- Edge e;
- e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
- if (e == null) {
- String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
- if (canBeLinked != null && canBeLinked.equals("true")) {
- Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext));
- boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
- if (isFirst) {
- child.property(AAIProperties.LINKED, true);
- }
- }
- edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
- }
- return child;
-
- }
-
- private SchemaVersion getVerForContext(String requestContext) {
- Pattern pattern = Pattern.compile("v[0-9]+");
- Matcher m = pattern.matcher(requestContext);
- if (!m.find()) {
- return this.version;
- } else {
- return new SchemaVersion(requestContext);
- }
- }
-
- /**
- * 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;
- }
- StopWatch.conditionalStart();
- if (vertices.size() > 1 && !obj.isContainer()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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<>();
-
- QueryEngine tgEngine = this.engine.getQueryEngine();
- for (Vertex v : vertices) {
-
- AaiCallable<Object> task = new AaiCallable<Object>() {
- @Override
- public Object process() throws UnsupportedEncodingException, AAIException {
- Set<Vertex> seen = new HashSet<>();
- Introspector childObject;
- try {
- childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
- } catch (AAIUnknownObjectException e) {
- throw e;
- }
- Tree<Element> tree = tgEngine.findSubGraph(v, internalDepth, nodeOnly);
- TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
- try {
- dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
- } catch (UnsupportedEncodingException e) {
- throw e;
- } catch (AAIException e) {
- throw e;
- }
- 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) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_4000", e);
- } catch (InterruptedException e) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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;
- }
-
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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;
-
- try {
- rule = edgeRules.getRule(new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build());
- } catch (EdgeRuleNotFoundException e) {
- throw new NoEdgeRuleFoundException(e);
- } catch (AmbiguousRuleChoiceException e) {
- throw new MultipleEdgeRuleFoundException(e);
- }
- 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.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;
- StopWatch.conditionalStart();
- this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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;
- StopWatch.conditionalStart();
- Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
- TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
- this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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) {
- if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
- List<Edge> edges = this.getEdgesBetween(EdgeType.COUSIN, v, cousin);
- for (Edge e : edges) {
- Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
- Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, e);
- if (result != null) {
- relationshipObjList.add(result);
- }
- }
- } else {
- Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
- Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
- 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 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, Edge edge) 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() + " " + LogFormatTools.getStackTop(e));
- if ("true".equals(cleanUp)) {
- this.deleteWithTraversal(tuple.get().getValue0());
- }
- return null;
- }
- if (!list.isEmpty()) {
- this.addRelatedToProperty(result, list.get(0));
- }
-
- if (edge != null && result.hasProperty("relationship-label")) {
- result.setValue("relationship-label", edge.label());
- }
-
- 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 {
- StopWatch.conditionalStart();
- Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(this.loader, v, false);
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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();
- return UriBuilder.fromPath(uri).build();
- }
-
- /**
- * 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));
- }
-
- /**
- * 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.isEmpty()) {
- 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;
- StopWatch.conditionalStart();
- QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
-
- String label = null;
- if (relationship.hasProperty("relationship-label")) {
- label = relationship.getValue("relationship-label");
- }
-
- List<Vertex> results = parser.getQueryBuilder().toList();
- if (results.isEmpty()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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, label);
- if (e == null) {
- edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
- } else {
- //attempted to link two vertexes already linked
- }
- } finally {
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
- }
-
- dbTimeMsecs += StopWatch.stopIfStarted();
- return true;
- }
-
- /**
- * Gets all the edges between of the type.
- *
- * @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) {
-
- List<Edge> result = new ArrayList<>();
-
- if (bVertex != null) {
- GraphTraversal<Vertex, Edge> findEdgesBetween = null;
- findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
- if (EdgeType.TREE.equals(type)) {
- findEdgesBetween = findEdgesBetween
- .not(
- __.or(
- __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
- __.has(EdgeField.PRIVATE.toString(), true)
- )
- );
- } else {
- findEdgesBetween = findEdgesBetween
- .has(EdgeProperty.CONTAINS.toString(), "NONE")
- .not(
- __.has(EdgeField.PRIVATE.toString(), true)
- );
- }
- findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
- result = findEdgesBetween.toList();
- }
-
- return result;
- }
- /**
- * Gets all the edges between the vertexes with the label and type.
- *
- * @param aVertex the out vertex
- * @param bVertex the in vertex
- * @param label
- * @return the edges between
- * @throws AAIException the AAI exception
- */
- private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
-
- List<Edge> result = new ArrayList<>();
-
- if (bVertex != null) {
- String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value();
- String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value();
- EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build();
- EdgeRule rule;
- try {
- rule = edgeRules.getRule(q);
- } catch (EdgeRuleNotFoundException e) {
- throw new NoEdgeRuleFoundException(e);
- } catch (AmbiguousRuleChoiceException e) {
- throw new MultipleEdgeRuleFoundException(e);
- }
- List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
- for (Edge edge : edges) {
- if (edge.label().equals(rule.getLabel())) {
- result.add(edge);
- }
- }
- }
-
- return result;
- }
-
- /**
- * Gets the edge between with the label and edge type.
- *
- * @param aVertex the out vertex
- * @param bVertex the in vertex
- * @param label
- * @return the edge between
- * @throws AAIException the AAI exception
- * @throws NoEdgeRuleFoundException
- */
- public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
-
- StopWatch.conditionalStart();
- if (bVertex != null) {
-
- List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex, label);
-
- if (!edges.isEmpty()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- return edges.get(0);
- }
-
- }
- dbTimeMsecs += StopWatch.stopIfStarted();
- return null;
- }
- public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
- return this.getEdgeBetween(type, aVertex, bVertex, 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;
- StopWatch.conditionalStart();
- QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
-
- List<Vertex> results = parser.getQueryBuilder().toList();
-
- String label = null;
- if (relationship.hasProperty("relationship-label")) {
- label = relationship.getValue("relationship-label");
- }
-
- if (results.isEmpty()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- return false;
- }
-
- relatedVertex = results.get(0);
- Edge edge;
- try {
- edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
- } catch (NoEdgeRuleFoundException e) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_6129", e);
- }
- if (edge != null) {
- edge.remove();
- dbTimeMsecs += StopWatch.stopIfStarted();
- return true;
- } else {
- dbTimeMsecs += StopWatch.stopIfStarted();
- 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) {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
+
+ private final TransactionalGraphEngine engine;
+ private final String sourceOfTruth;
+ private final ModelType introspectionType;
+ private final SchemaVersion version;
+ private final Loader latestLoader;
+ private EdgeSerializer edgeSer;
+ private EdgeIngestor edgeRules;
+ private final Loader loader;
+ private final String baseURL;
+ private double dbTimeMsecs = 0;
+ private long currentTimeMillis;
+
+ private SchemaVersions schemaVersions;
+ private Set<String> namedPropNodes;
+ /**
+ * Instantiates a new DB serializer.
+ *
+ * @param version the version
+ * @param engine the engine
+ * @param introspectionType the introspection type
+ * @param sourceOfTruth the source of truth
+ * @throws AAIException
+ */
+ public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
+ this.engine = engine;
+ this.sourceOfTruth = sourceOfTruth;
+ this.introspectionType = introspectionType;
+ this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
+ SchemaVersion LATEST = schemaVersions.getDefaultVersion();
+ this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST);
+ this.version = version;
+ this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version);
+ this.namedPropNodes = this.latestLoader.getNamedPropNodes();
+ this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
+ this.currentTimeMillis = System.currentTimeMillis();
+ initBeans();
+ }
+
+ private void initBeans() {
+ //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
+ ApplicationContext ctx = SpringContextAware.getApplicationContext();
+ EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
+ setEdgeIngestor(ei);
+ EdgeSerializer es = ctx.getBean(EdgeSerializer.class);
+ setEdgeSerializer(es);
+ }
+
+ private void backupESInit() {
+ setEdgeSerializer(new EdgeSerializer(this.edgeRules));
+ }
+
+ public void setEdgeSerializer(EdgeSerializer edgeSer) {
+ this.edgeSer = edgeSer;
+ }
+
+ public EdgeSerializer getEdgeSeriailizer() {
+ return this.edgeSer;
+ }
+
+ public void setEdgeIngestor(EdgeIngestor ei) {
+ this.edgeRules = ei;
+ }
+
+ public EdgeIngestor getEdgeIngestor() {
+ return this.edgeRules;
+ }
+
+ /**
+ * Touch standard vertex properties.
+ *
+ * @param v the v
+ * @param isNewVertex the is new vertex
+ */
+ public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
+ String timeNowInSec = Long.toString(currentTimeMillis);
+
+ if (isNewVertex) {
+ v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
+ v.property(AAIProperties.CREATED_TS, timeNowInSec);
+ v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
+ }
+ 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;
+ try {
+ StopWatch.conditionalStart();
+ v = this.engine.tx().addVertex();
+ touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
+ } finally {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+ 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 {
+ StopWatch.conditionalStart();
+ 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 {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
+ }
+ } else {
+ serializeSingleVertex(v, obj, requestContext);
+ }
+
+ } catch (SchemaViolationException e) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_6117", e);
+ }
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+
+ public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
+ StopWatch.conditionalStart();
+ try {
+ boolean isTopLevel = obj.isTopLevel();
+ if (isTopLevel) {
+ addUriIfNeeded(v, obj.getURI());
+ }
+
+ processObject(obj, v, requestContext);
+ if (!isTopLevel) {
+ URI uri = this.getURIForVertex(v);
+ URIParser parser = new URIParser(this.loader, uri);
+ if (parser.validate()) {
+ addUriIfNeeded(v, uri.toString());
+ }
+ }
+ } catch (SchemaViolationException e) {
+ throw new AAIException("AAI_6117", e);
+ } finally {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+ }
+
+ private void addUriIfNeeded(Vertex v, String uri) {
+ VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
+ if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) {
+ v.property(AAIProperties.AAI_URI, uri);
+ }
+ }
+
+ /**
+ * 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<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
+ List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
+
+ for (Object relationship : relationships) {
+ Edge e = null;
+ Vertex cousinVertex = null;
+ String label = null;
+ Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
+
+ if (wrappedRel.hasProperty("relationship-label")) {
+ label = wrappedRel.getValue("relationship-label");
+ }
+
+ 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) {
+ String vType = (String) v.property(AAIProperties.NODE_TYPE).value();
+ String cousinType = (String) cousinVertex.property(AAIProperties.NODE_TYPE).value();
+ EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label);
+
+
+ if (!edgeRules.hasRule(baseQ.build())) {
+ 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() + (label != null ? (" with label " + label) : "") + ".");
+ } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
+ throw new AAIException("AAI_6145");
+ }
+
+ e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
+
+ if (e == null) {
+ addEdges.add(new Triplet<>(v, cousinVertex, label));
+ } else {
+ existingEdges.remove(e);
+ }
+ }
+ }
+
+ for (Edge edge : existingEdges) {
+ edge.remove();
+ }
+ for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
+ try {
+ edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2());
+ } 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<Vertex> 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();
+ addUriIfNeeded(child, parentUri + uri);
+ }
+ processObject(obj, child, requestContext);
+
+ Edge e;
+ e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
+
+ if (e == null) {
+ String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
+ if (canBeLinked != null && canBeLinked.equals("true")) {
+ Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext));
+ boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
+ if (isFirst) {
+ child.property(AAIProperties.LINKED, true);
+ }
+ }
+ edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
+ }
+ return child;
+
+ }
+
+ private SchemaVersion getVerForContext(String requestContext) {
+ Pattern pattern = Pattern.compile("v[0-9]+");
+ Matcher m = pattern.matcher(requestContext);
+ if (!m.find()) {
+ return this.version;
+ } else {
+ return new SchemaVersion(requestContext);
+ }
+ }
+
+ /**
+ * 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;
+ }
+ StopWatch.conditionalStart();
+ if (vertices.size() > 1 && !obj.isContainer()) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ 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<>();
+
+ QueryEngine tgEngine = this.engine.getQueryEngine();
+ for (Vertex v : vertices) {
+
+ AaiCallable<Object> task = new AaiCallable<Object>() {
+ @Override
+ public Object process() throws UnsupportedEncodingException, AAIException {
+ Set<Vertex> seen = new HashSet<>();
+ Introspector childObject;
+ try {
+ childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
+ } catch (AAIUnknownObjectException e) {
+ throw e;
+ }
+ try {
+ dbToObject(childObject, v, seen, internalDepth, nodeOnly, cleanUp);
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ } catch (AAIException e) {
+ throw e;
+ }
+ 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) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_4000", e);
+ } catch (InterruptedException e) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_4000", e);
+ }
+ }
+ } else if (vertices.size() == 1) {
+ Set<Vertex> seen = new HashSet<>();
+ dbToObject(obj, vertices.get(0), seen, depth, nodeOnly, cleanUp);
+ } else {
+ //obj = null;
+ }
+
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ 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;
+
+ try {
+ rule = edgeRules.getRule(new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build());
+ } catch (EdgeRuleNotFoundException e) {
+ throw new NoEdgeRuleFoundException(e);
+ } catch (AmbiguousRuleChoiceException e) {
+ throw new MultipleEdgeRuleFoundException(e);
+ }
+ 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.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;
+ StopWatch.conditionalStart();
+ this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ 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;
+ StopWatch.conditionalStart();
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
+ this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ 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);
+ }
+ }
+
+
+ /**
+ * Load the introspector from the hashmap for the given property key
+ *
+ * @param property - vertex property
+ * @param obj - introspector object representing the vertex
+ * @param hashMap - Containing a list of pre-fetched properties for a given vertex
+ */
+ private void copySimplePropertyFromHashMap(String property, Introspector obj, Map<String, Object> hashMap){
+
+ 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 = hashMap.getOrDefault(dbPropertyName, 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 key : obj.getProperties()){
+ this.copySimpleProperty(key, obj, v);
+ }
+ }
+
+
+ public Map<String, Object> convertVertexToHashMap(Introspector obj, Vertex v){
+
+ long startTime = System.currentTimeMillis();
+
+ Set<String> simpleProperties = obj.getSimpleProperties(PropertyPredicates.isVisible());
+ String[] simplePropsArray = new String[simpleProperties.size()];
+ simplePropsArray = simpleProperties.toArray(simplePropsArray);
+
+ Map<String, Object> simplePropsHashMap = new HashMap<>(simplePropsArray.length * 2);
+
+ v.properties(simplePropsArray).forEachRemaining((vp) -> simplePropsHashMap.put(vp.key(), vp.value()));
+
+ return simplePropsHashMap;
+ }
+
+ /**
+ * 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 {
+
+ String[] cousinRules = new String[0];
+
+ try {
+ cousinRules = edgeRules.retrieveCachedCousinLabels(obj.getDbName());
+ } catch (ExecutionException e) {
+ LOGGER.warn("Encountered an execution exception while retrieving labels for the node type {} using cached", obj.getDbName(), e);
+ }
+
+ List<Vertex> cousins = null;
+ if(cousinRules != null && cousinRules.length != 0){
+ cousins = this.engine.getQueryEngine().findCousinVertices(v, cousinRules);
+ } else {
+ cousins = this.engine.getQueryEngine().findCousinVertices(v);
+ }
+
+ List<Object> relationshipObjList = obj.getValue("relationship");
+ String aNodeType = v.property("aai-node-type").value().toString();
+
+ TypeAlphabetizer alphabetizer = new TypeAlphabetizer();
+
+ EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class);
+ Set<String> keysWithMultipleLabels = edgeIngestor.getMultipleLabelKeys();
+
+ // For the given vertex, find all the cousins
+ // For each cousin retrieve the node type and then
+ // check if the version is greater than the edge label version
+ // meaning is the current version equal to greater than the version
+ // where we introduced the edge labels into the relationship payload
+ // If it is, then we check if the edge key there are multiple labels
+ // If there are multiple labels, then we need to go to the database
+ // to retrieve the labels between itself and cousin vertex
+ // If there is only single label between the edge a and b, then
+ // we can retrieve what that is without going to the database
+ // from using the edge rules json and get the edge rule out of it
+ EdgeRuleQuery.Builder queryBuilder = new EdgeRuleQuery.Builder(aNodeType);
+ for (Vertex cousin : cousins) {
+ VertexProperty vertexProperty = cousin.property("aai-node-type");
+ String bNodeType = null;
+ if(vertexProperty.isPresent()){
+ bNodeType = cousin.property("aai-node-type").value().toString();
+ } else {
+ // If the vertex is missing the aai-node-type
+ // Then its either a bad vertex or its in the process
+ // of getting deleted so we should ignore these vertexes
+ if(LOGGER.isDebugEnabled()){
+ LOGGER.debug("For the vertex {}, unable to retrieve the aai-node-type", v.id().toString());
+ } else {
+ LOGGER.info("Unable to retrieve the aai-node-type for vertex, for more info enable debug log");
+ }
+ continue;
+ }
+ if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
+ String edgeKey = alphabetizer.buildAlphabetizedKey(aNodeType, bNodeType);
+ if(keysWithMultipleLabels.contains(edgeKey)){
+ List<String> edgeLabels = this.getEdgeLabelsBetween(EdgeType.COUSIN, v, cousin);
+ for(String edgeLabel: edgeLabels){
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, edgeLabel);
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+ }
+ } else {
+
+ EdgeRule edgeRule = null;
+
+ // Create a query based on the a nodetype and b nodetype
+ // which is also a cousin edge and ensure the version
+ // is used properly so for example in order to be backwards
+ // compatible if we had allowed a edge between a and b
+ // in a previous release and we decided to remove it from
+ // the edge rules in the future we can display the edge
+ // only for the older apis and the new apis if the edge rule
+ // is removed will not be seen in the newer version of the API
+
+ EdgeRuleQuery ruleQuery = queryBuilder
+ .to(bNodeType)
+ .edgeType(EdgeType.COUSIN)
+ .version(obj.getVersion())
+ .build();
+
+ try {
+ edgeRule = edgeIngestor.getRule(ruleQuery);
+ } catch (EdgeRuleNotFoundException e) {
+ LOGGER.warn("Caught an edge rule not found exception for query {}, {}," +
+ " it could be the edge rule is no longer valid for the existing edge in db",
+ ruleQuery, LogFormatTools.getStackTop(e));
+ continue;
+ } catch (AmbiguousRuleChoiceException e) {
+ LOGGER.error("Caught an ambiguous rule not found exception for query {}, {}",
+ ruleQuery, LogFormatTools.getStackTop(e));
+ continue;
+ }
+
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp,edgeRule.getLabel());
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+ }
+ } else {
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
+ 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 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, String edgeLabel) throws UnsupportedEncodingException, AAIUnknownObjectException {
+
+ VertexProperty aaiUriProperty = cousin.property("aai-uri");
+
+ if(!aaiUriProperty.isPresent()){
+ return null;
+ }
+
+ URI uri = UriBuilder.fromUri(aaiUriProperty.value().toString()).build();
+
+ 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=" + ": "
+ + e.getMessage() + " " + LogFormatTools.getStackTop(e));
+ return null;
+ }
+
+ VertexProperty cousinVertexNodeType = cousin.property(AAIProperties.NODE_TYPE);
+
+ if(cousinVertexNodeType.isPresent()){
+ if(namedPropNodes.contains(cousinVertexNodeType.value().toString())){
+ Introspector cousinObj = loader.introspectorFromName(cousinVertexNodeType.value().toString());
+ this.simpleDbToObject(cousinObj, cousin);
+ this.addRelatedToProperty(result, cousinObj);
+ }
+ }
+
+ if (edgeLabel != null && result.hasProperty("relationship-label")) {
+ result.setValue("relationship-label", edgeLabel);
+ }
+
+ 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();
+ }
+
+ 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();
+ return UriBuilder.fromPath(uri).build();
+ }
+
+ /**
+ * Adds the r
+ *
+ * @param relationship the relationship
+ * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
+ * @throws AAIUnknownObjectException
+ * @throws IllegalArgumentException elated to property.
+ */
+ 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.isEmpty()) {
+ 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;
+ StopWatch.conditionalStart();
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ String label = null;
+ if (relationship.hasProperty("relationship-label")) {
+ label = relationship.getValue("relationship-label");
+ }
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+ if (results.isEmpty()) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ 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, label);
+ if (e == null) {
+ edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
+ } else {
+ //attempted to link two vertexes already linked
+ }
+ } finally {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+ }
+
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return true;
+ }
+
+ /**
+ * Gets all the edges between of the type with the specified label.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private Edge getEdgeBetweenWithLabel(EdgeType type, Vertex aVertex, Vertex bVertex, EdgeRule edgeRule) {
+
+ Edge result = null;
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ if (EdgeType.TREE.equals(type)) {
+ GraphTraversal<Vertex,Vertex> findVertex = this.engine.asAdmin().getTraversalSource().V(bVertex);
+ if(edgeRule.getDirection().equals(Direction.IN)){
+ findEdgesBetween = findVertex.outE(edgeRule.getLabel())
+ .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains())
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ } else {
+ findEdgesBetween = findVertex.inE(edgeRule.getLabel())
+ .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains())
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ }
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(aVertex.id())).limit(1);
+ } else {
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(edgeRule.getLabel());
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id())).limit(1);
+ }
+ List<Edge> list = findEdgesBetween.toList();
+ if(!list.isEmpty()){
+ result = list.get(0);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets all the edges between of the type.
+ *
+ * @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) {
+
+ List<Edge> result = new ArrayList<>();
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
+ if (EdgeType.TREE.equals(type)) {
+ findEdgesBetween = findEdgesBetween
+ .not(
+ __.or(
+ __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
+ __.has(EdgeField.PRIVATE.toString(), true)
+ )
+ );
+ } else {
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ }
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
+ result = findEdgesBetween.toList();
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets all the edges string between of the type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private List<String> getEdgeLabelsBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
+
+ List<String> result = new ArrayList<>();
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
+ if (EdgeType.TREE.equals(type)) {
+ findEdgesBetween = findEdgesBetween
+ .not(
+ __.or(
+ __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
+ __.has(EdgeField.PRIVATE.toString(), true)
+ )
+ );
+ } else {
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ }
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
+ result = findEdgesBetween.label().toList();
+ }
+ return result;
+ }
+
+ /**
+ * Gets all the edges string between of the type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private Long getEdgeLabelsCount(Vertex aVertex, Vertex bVertex) {
+
+ Long result = null;
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
+ result = findEdgesBetween.count().next();
+ }
+ return result;
+ }
+ /**
+ * Gets all the edges between the vertexes with the label and type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @param label
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ */
+ private Edge getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
+
+ Edge edge = null;
+
+ if (bVertex != null) {
+ String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value();
+ String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value();
+ EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build();
+ EdgeRule rule;
+ try {
+ rule = edgeRules.getRule(q);
+ } catch (EdgeRuleNotFoundException e) {
+ throw new NoEdgeRuleFoundException(e);
+ } catch (AmbiguousRuleChoiceException e) {
+ throw new MultipleEdgeRuleFoundException(e);
+ }
+ edge = this.getEdgeBetweenWithLabel(type, aVertex, bVertex, rule);
+ }
+
+ return edge;
+ }
+
+ /**
+ * Gets the edge between with the label and edge type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @param label
+ * @return the edge between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
+
+ StopWatch.conditionalStart();
+ if (bVertex != null) {
+
+ Edge edge = this.getEdgesBetween(type, aVertex, bVertex, label);
+ if (edge != null) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return edge;
+ }
+
+ }
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return null;
+ }
+
+ public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.getEdgeBetween(type, aVertex, bVertex, 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;
+ StopWatch.conditionalStart();
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+
+ String label = null;
+ if (relationship.hasProperty("relationship-label")) {
+ label = relationship.getValue("relationship-label");
+ }
+
+ if (results.isEmpty()) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return false;
+ }
+
+ relatedVertex = results.get(0);
+ Edge edge;
+ try {
+ edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
+ } catch (NoEdgeRuleFoundException e) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_6129", e);
+ }
+ if (edge != null) {
+ edge.remove();
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return true;
+ } else {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ 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) {
- StopWatch.conditionalStart();
- List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
-
- for (Vertex v : results) {
- LOGGER.warn("Removing vertex " + v.id().toString());
-
- v.remove();
- }
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
-
- /**
- * 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, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
-
- boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
- /*
- * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain
- * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted
- * So its better to make these in 2 steps
- */
- if(result && !deletableVertices.isEmpty()){
- result = verifyPreventDeleteSemantics(deletableVertices);
- }
- if (result) {
-
- try {
- deleteWithTraversal(v);
- } catch (IllegalStateException e) {
- throw new AAIException("AAI_6110", e);
- }
-
- }
-
- }
-
-
- /**
- * 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<Vertex> vertices = new ArrayList<Vertex>();
- vertices.add(vertex);
- result = verifyPreventDeleteSemantics(vertices);
-
- return result;
- }
-
- /**
- * Verify Prevent delete semantics.
- * @param vertices the list of vertices
- * @return true, if successful
- * @throws AAIException the AAI exception
- */
- private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException {
- boolean result = true;
- String nodeType = "";
- String errorDetail = " unknown delete semantic found";
- String aaiExceptionCode = "";
-
- StopWatch.conditionalStart();
- /*
- * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition
- * If yes - that should prevent the deletion of the vertex
- * Dedup makes sure we dont capture the prevent-delete vertices twice
- * The prevent-delete vertices are stored so that the error message displays what prevents the delete
- */
-
- List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices).
- 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();
-
- dbTimeMsecs += StopWatch.stopIfStarted();
- if (!preventDeleteVertices.isEmpty()) {
- 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);
- }
- if (enabled.equals("true")) {
- 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).addSideEffect(PrivateEdge.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);
- }
-
- public double getDBTimeMsecs() {
- return (dbTimeMsecs);
- }
-
- /**
- * Db to object With Filters
- * This is for a one-time run with Tenant Isloation to only filter relationships
- * TODO: Chnage the original dbToObject to take filter parent/cousins
- *
- * @param obj the obj
- * @param v the vertex from the graph
- * @param depth the depth
- * @param nodeOnly specify if to exclude relationships or not
- * @param filterCousinNodes
- * @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
- */
- //TODO - See if you can merge the 2 dbToObjectWithFilters
- public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, List<String> filterCousinNodes, List<String> filterParentNodes) throws AAIException, UnsupportedEncodingException {
- String cleanUp = "false";
- 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 = dbToObjectWithFilters(argumentObject, v, seen, depth+1, nodeOnly, filterCousinNodes, filterParentNodes);
- 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 = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
- 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;
-
- boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains);
-
- EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build();
-
- try {
- rule = edgeRules.getRule(q);
- } catch (EdgeRuleNotFoundException e) {
- throw new NoEdgeRuleFoundException(e);
- } catch (AmbiguousRuleChoiceException e) {
- throw new MultipleEdgeRuleFoundException(e);
- }
- if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
- //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 = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes);
- if (result != 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;
-
- }
-
- /**
- * Creates the relationship list with the filtered node types.
- *
- * @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 createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
- List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
-
- Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
- String node = (String)item.property(AAIProperties.NODE_TYPE).orElse("");
- return filterNodes.parallelStream().anyMatch(node::contains);
- }).iterator();
-
-
- List<Vertex> cousins = (List<Vertex>)IteratorUtils.toList(cousinVertices);
-
- //items.parallelStream().anyMatch(inputStr::contains)
- List<Object> relationshipObjList = obj.getValue("relationship");
- for (Vertex cousin : cousins) {
-
- Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
- Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
- if (result != null) {
- relationshipObjList.add(result);
- }
-
-
- }
-
- if (relationshipObjList.isEmpty()) {
- return null;
- } else {
- return obj;
- }
- }
+ deleteWithTraversal(v);
+ }
+
+ }
+
+ /**
+ * Delete with traversal.
+ *
+ * @param startVertex the start vertex
+ */
+ public void deleteWithTraversal(Vertex startVertex) {
+ StopWatch.conditionalStart();
+ List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
+
+ for (Vertex v : results) {
+ LOGGER.warn("Removing vertex " + v.id().toString());
+
+ v.remove();
+ }
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+
+ /**
+ * 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, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
+
+ boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
+ /*
+ * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain
+ * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted
+ * So its better to make these in 2 steps
+ */
+ if (result && !deletableVertices.isEmpty()) {
+ result = verifyPreventDeleteSemantics(deletableVertices);
+ }
+ if (result) {
+
+ try {
+ deleteWithTraversal(v);
+ } catch (IllegalStateException e) {
+ throw new AAIException("AAI_6110", e);
+ }
+
+ }
+
+ }
+
+
+ /**
+ * 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<Vertex> vertices = new ArrayList<Vertex>();
+ vertices.add(vertex);
+ result = verifyPreventDeleteSemantics(vertices);
+
+ return result;
+ }
+
+ /**
+ * Verify Prevent delete semantics.
+ *
+ * @param vertices the list of vertices
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException {
+ boolean result = true;
+ String nodeType = "";
+ String errorDetail = " unknown delete semantic found";
+ String aaiExceptionCode = "";
+
+ StopWatch.conditionalStart();
+ /*
+ * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition
+ * If yes - that should prevent the deletion of the vertex
+ * Dedup makes sure we dont capture the prevent-delete vertices twice
+ * The prevent-delete vertices are stored so that the error message displays what prevents the delete
+ */
+
+ List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices).
+ 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();
+
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ if (!preventDeleteVertices.isEmpty()) {
+ 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);
+ }
+ if (enabled.equals("true")) {
+ 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).addSideEffect(PrivateEdge.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);
+ }
+
+ public double getDBTimeMsecs() {
+ return (dbTimeMsecs);
+ }
+
+ /**
+ * Db to object With Filters
+ * This is for a one-time run with Tenant Isloation to only filter relationships
+ * TODO: Chnage the original dbToObject to take filter parent/cousins
+ *
+ * @param obj the obj
+ * @param v the vertex from the graph
+ * @param depth the depth
+ * @param nodeOnly specify if to exclude relationships or not
+ * @param filterCousinNodes
+ * @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
+ */
+ //TODO - See if you can merge the 2 dbToObjectWithFilters
+ public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, List<String> filterCousinNodes, List<String> filterParentNodes) throws AAIException, UnsupportedEncodingException {
+ String cleanUp = "false";
+ 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 = dbToObjectWithFilters(argumentObject, v, seen, depth + 1, nodeOnly, filterCousinNodes, filterParentNodes);
+ 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 = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
+ 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;
+
+ boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains);
+
+ EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build();
+
+ try {
+ rule = edgeRules.getRule(q);
+ } catch (EdgeRuleNotFoundException e) {
+ throw new NoEdgeRuleFoundException(e);
+ } catch (AmbiguousRuleChoiceException e) {
+ throw new MultipleEdgeRuleFoundException(e);
+ }
+ if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
+ //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 = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes);
+ if (result != 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;
+
+ }
+
+ /**
+ * Creates the relationship list with the filtered node types.
+ *
+ * @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 createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
+ List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
+
+ Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
+ String node = (String) item.property(AAIProperties.NODE_TYPE).orElse("");
+ return filterNodes.parallelStream().anyMatch(node::contains);
+ }).iterator();
+
+
+ List<Vertex> cousins = (List<Vertex>) IteratorUtils.toList(cousinVertices);
+
+ //items.parallelStream().anyMatch(inputStr::contains)
+ List<Object> relationshipObjList = obj.getValue("relationship");
+ for (Vertex cousin : cousins) {
+
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+
+
+ }
+
+ if (relationshipObjList.isEmpty()) {
+ return null;
+ } else {
+ return obj;
+ }
+ }
}