2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
20 package org.onap.aai.serialization.db;
23 import com.att.eelf.configuration.EELFLogger;
24 import com.att.eelf.configuration.EELFManager;
25 import com.google.common.base.CaseFormat;
26 import org.janusgraph.core.SchemaViolationException;
27 import org.apache.commons.collections.IteratorUtils;
28 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
29 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
30 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
31 import org.apache.tinkerpop.gremlin.structure.*;
32 import org.javatuples.Pair;
33 import org.javatuples.Triplet;
34 import org.onap.aai.db.props.AAIProperties;
35 import org.onap.aai.edges.EdgeIngestor;
36 import org.onap.aai.edges.EdgeRule;
37 import org.onap.aai.edges.EdgeRuleQuery;
38 import org.onap.aai.edges.enums.AAIDirection;
39 import org.onap.aai.edges.enums.EdgeField;
40 import org.onap.aai.edges.enums.EdgeProperty;
41 import org.onap.aai.edges.enums.EdgeType;
42 import org.onap.aai.edges.exceptions.AmbiguousRuleChoiceException;
43 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
44 import org.onap.aai.exceptions.AAIException;
45 import org.onap.aai.introspection.*;
46 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
47 import org.onap.aai.introspection.sideeffect.*;
48 import org.onap.aai.logging.ErrorLogHelper;
49 import org.onap.aai.logging.LogFormatTools;
50 import org.onap.aai.logging.StopWatch;
51 import org.onap.aai.parsers.query.QueryParser;
52 import org.onap.aai.parsers.uri.URIParser;
53 import org.onap.aai.parsers.uri.URIToRelationshipObject;
54 import org.onap.aai.query.builder.QueryBuilder;
55 import org.onap.aai.schema.enums.ObjectMetadata;
56 import org.onap.aai.schema.enums.PropertyMetadata;
57 import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
58 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
59 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
60 import org.onap.aai.serialization.tinkerpop.TreeBackedVertex;
61 import org.onap.aai.setup.SchemaVersion;
62 import org.onap.aai.setup.SchemaVersions;
63 import org.onap.aai.util.AAIConfig;
64 import org.onap.aai.util.AAIConstants;
65 import org.onap.aai.workarounds.NamingExceptions;
66 import org.springframework.context.ApplicationContext;
67 import org.onap.aai.concurrent.AaiCallable;
68 import org.onap.aai.config.SpringContextAware;
70 import javax.ws.rs.core.UriBuilder;
71 import java.io.UnsupportedEncodingException;
72 import java.lang.reflect.Array;
73 import java.lang.reflect.InvocationTargetException;
74 import java.net.MalformedURLException;
76 import java.net.URISyntaxException;
78 import java.util.concurrent.ExecutionException;
79 import java.util.concurrent.ExecutorService;
80 import java.util.concurrent.Future;
81 import java.util.regex.Matcher;
82 import java.util.regex.Pattern;
83 import org.onap.aai.serialization.engines.query.QueryEngine;
85 public class DBSerializer {
87 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
89 private final TransactionalGraphEngine engine;
90 private final String sourceOfTruth;
91 private final ModelType introspectionType;
92 private final SchemaVersion version;
93 private final Loader latestLoader;
94 private EdgeSerializer edgeSer;
95 private EdgeIngestor edgeRules;
96 private final Loader loader;
97 private final String baseURL;
98 private double dbTimeMsecs = 0;
99 private long currentTimeMillis;
101 private SchemaVersions schemaVersions;
103 * Instantiates a new DB serializer.
105 * @param version the version
106 * @param engine the engine
107 * @param introspectionType the introspection type
108 * @param sourceOfTruth the source of truth
109 * @throws AAIException
111 public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
112 this.engine = engine;
113 this.sourceOfTruth = sourceOfTruth;
114 this.introspectionType = introspectionType;
115 this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
116 SchemaVersion LATEST = schemaVersions.getDefaultVersion();
117 this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST);
118 this.version = version;
119 this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version);
120 this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
121 this.currentTimeMillis = System.currentTimeMillis();
125 private void initBeans() {
126 //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
127 ApplicationContext ctx = SpringContextAware.getApplicationContext();
128 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
130 EdgeSerializer es = ctx.getBean(EdgeSerializer.class);
131 setEdgeSerializer(es);
134 private void backupESInit() {
135 setEdgeSerializer(new EdgeSerializer(this.edgeRules));
138 public void setEdgeSerializer(EdgeSerializer edgeSer) {
139 this.edgeSer = edgeSer;
142 public EdgeSerializer getEdgeSeriailizer() {
146 public void setEdgeIngestor(EdgeIngestor ei) {
150 public EdgeIngestor getEdgeIngestor(){
151 return this.edgeRules;
155 * Touch standard vertex properties.
158 * @param isNewVertex the is new vertex
160 public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
161 String timeNowInSec = Long.toString(currentTimeMillis);
164 v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
165 v.property(AAIProperties.CREATED_TS, timeNowInSec);
166 v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
168 v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec);
169 v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
170 v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
174 private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) {
176 v.property(AAIProperties.NODE_TYPE, nodeType);
177 touchStandardVertexProperties(v, isNewVertex);
184 * Creates the new vertex.
186 * @param wrappedObject the wrapped object
188 * @throws UnsupportedEncodingException the unsupported encoding exception
189 * @throws AAIException the AAI exception
191 public Vertex createNewVertex(Introspector wrappedObject) {
194 StopWatch.conditionalStart();
195 v = this.engine.tx().addVertex();
196 touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
199 dbTimeMsecs += StopWatch.stopIfStarted();
207 * @param className the class name
211 * Removes the classpath from a class name
213 public String trimClassName (String className) {
214 String returnValue = "";
216 if (className.lastIndexOf('.') == -1) {
219 returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
229 * @param uriQuery the uri query
230 * @param identifier the identifier
231 * @throws SecurityException the security exception
232 * @throws IllegalAccessException the illegal access exception
233 * @throws IllegalArgumentException the illegal argument exception
234 * @throws InvocationTargetException the invocation target exception
235 * @throws InstantiationException the instantiation exception
236 * @throws InterruptedException the interrupted exception
237 * @throws NoSuchMethodException the no such method exception
238 * @throws AAIException the AAI exception
239 * @throws UnsupportedEncodingException the unsupported encoding exception
240 * @throws AAIUnknownObjectException
242 public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
243 StopWatch.conditionalStart();
245 if (uriQuery.isDependent()) {
246 //try to find the parent
247 List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
248 if (!vertices.isEmpty()) {
249 Vertex parent = vertices.get(0);
250 this.reflectDependentVertex(parent, v, obj, requestContext);
252 dbTimeMsecs += StopWatch.stopIfStarted();
253 throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
256 serializeSingleVertex(v, obj, requestContext);
259 } catch (SchemaViolationException e) {
260 dbTimeMsecs += StopWatch.stopIfStarted();
261 throw new AAIException("AAI_6117", e);
263 dbTimeMsecs += StopWatch.stopIfStarted();
266 public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
267 StopWatch.conditionalStart();
269 boolean isTopLevel = obj.isTopLevel();
271 addUriIfNeeded(v, obj.getURI());
274 processObject(obj, v, requestContext);
276 URI uri = this.getURIForVertex(v);
277 URIParser parser = new URIParser(this.loader, uri);
278 if (parser.validate()) {
279 addUriIfNeeded(v, uri.toString());
282 } catch (SchemaViolationException e) {
283 throw new AAIException("AAI_6117", e);
286 dbTimeMsecs += StopWatch.stopIfStarted();
290 private void addUriIfNeeded(Vertex v, String uri) {
291 VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
292 if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) {
293 v.property(AAIProperties.AAI_URI, uri);
300 * @param <T> the generic type
304 * @throws IllegalAccessException the illegal access exception
305 * @throws IllegalArgumentException the illegal argument exception
306 * @throws InvocationTargetException the invocation target exception
307 * @throws InstantiationException the instantiation exception
308 * @throws NoSuchMethodException the no such method exception
309 * @throws SecurityException the security exception
310 * @throws AAIException the AAI exception
311 * @throws UnsupportedEncodingException the unsupported encoding exception
312 * @throws AAIUnknownObjectException
315 * Helper method for reflectToDb
316 * Handles all the property setting
318 private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
319 Set<String> properties = new LinkedHashSet<>(obj.getProperties());
320 properties.remove(AAIProperties.RESOURCE_VERSION);
321 List<Vertex> dependentVertexes = new ArrayList<>();
322 List<Vertex> processedVertexes = new ArrayList<>();
323 boolean isComplexType = false;
324 boolean isListType = false;
325 if (!obj.isContainer()) {
326 this.touchStandardVertexProperties(obj.getDbName(), v, false);
328 this.executePreSideEffects(obj, v);
329 for (String property : properties) {
331 final String propertyType;
332 propertyType = obj.getType(property);
333 isComplexType = obj.isComplexType(property);
334 isListType = obj.isListType(property);
335 value = obj.getValue(property);
337 if (!(isComplexType || isListType)) {
338 boolean canModify = this.canModify(obj, property, requestContext);
341 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
342 String dbProperty = property;
343 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
344 dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
346 if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
347 //data linked properties are ephemeral
348 //they are populated dynamically on GETs
352 if (!value.equals(v.property(dbProperty).orElse(null))) {
353 if (propertyType.toLowerCase().contains(".long")) {
354 v.property(dbProperty, new Integer(((Long)value).toString()));
356 v.property(dbProperty, value);
360 v.property(dbProperty).remove();
363 } else if (isListType) {
364 List<Object> list = (List<Object>)value;
365 if (obj.isComplexGenericType(property)) {
367 for (Object o : list) {
368 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
369 child.setURIChain(obj.getURI());
370 processedVertexes.add(reflectDependentVertex(v, child, requestContext));
375 engine.setListProperty(v, property, list);
378 //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
379 if (value != null) { //effectively ignore complex properties not included in the object we're processing
380 if (value.getClass().isArray()) {
382 int length = Array.getLength(value);
383 for (int i = 0; i < length; i ++) {
384 Object arrayElement = Array.get(value, i);
385 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
386 child.setURIChain(obj.getURI());
387 processedVertexes.add(reflectDependentVertex(v, child, requestContext));
390 } else if (!property.equals("relationship-list")) {
392 Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
393 if (introspector.isContainer()) {
394 dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
395 introspector.setURIChain(obj.getURI());
397 processedVertexes.addAll(processObject(introspector, v, requestContext));
400 dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
401 processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
404 } else if (property.equals("relationship-list")) {
405 handleRelationships(obj, v);
410 this.writeThroughDefaults(v, obj);
411 /* handle those vertexes not touched */
412 for (Vertex toBeRemoved : processedVertexes) {
413 dependentVertexes.remove(toBeRemoved);
415 this.deleteItemsWithTraversal(dependentVertexes);
417 this.executePostSideEffects(obj, v);
418 return processedVertexes;
422 * Handle relationships.
425 * @param vertex the vertex
426 * @throws SecurityException the security exception
427 * @throws IllegalAccessException the illegal access exception
428 * @throws IllegalArgumentException the illegal argument exception
429 * @throws InvocationTargetException the invocation target exception
430 * @throws UnsupportedEncodingException the unsupported encoding exception
431 * @throws AAIException the AAI exception
434 * Handles the explicit relationships defined for an obj
436 private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
440 Introspector wrappedRl = obj.getWrappedValue("relationship-list");
441 processRelationshipList(wrappedRl, vertex);
448 * Process relationship list.
450 * @param wrapped the wrapped
452 * @throws UnsupportedEncodingException the unsupported encoding exception
453 * @throws AAIException the AAI exception
455 private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
457 List<Object> relationships = (List<Object>)wrapped.getValue("relationship");
459 List<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
460 List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
462 for (Object relationship : relationships) {
464 Vertex cousinVertex = null;
466 Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
467 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
469 if (wrappedRel.hasProperty("relationship-label")) {
470 label = wrappedRel.getValue("relationship-label");
473 List<Vertex> results = parser.getQueryBuilder().toList();
474 if (results.isEmpty()) {
475 final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
476 ex.getTemplateVars().add(parser.getResultType());
477 ex.getTemplateVars().add(parser.getUri().toString());
480 //still an issue if there's more than one
481 cousinVertex = results.get(0);
484 if (cousinVertex != null) {
485 String vType = (String)v.property(AAIProperties.NODE_TYPE).value();
486 String cousinType = (String)cousinVertex.property(AAIProperties.NODE_TYPE).value();
487 EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label);
490 if (!edgeRules.hasRule(baseQ.build())) {
491 throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + v.property(AAIProperties.NODE_TYPE).value().toString() + ", "
492 + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString() + (label != null ? (" with label " + label):"") +".");
493 } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
494 throw new AAIException("AAI_6145");
497 e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
500 addEdges.add(new Triplet<>(v, cousinVertex, label));
502 existingEdges.remove(e);
507 for (Edge edge : existingEdges) {
510 for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
512 edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2());
513 } catch (NoEdgeRuleFoundException e) {
514 throw new AAIException("AAI_6129", e);
521 * Write through defaults.
525 * @throws AAIUnknownObjectException
527 private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
528 Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
529 if (latest != null) {
530 Set<String> required = latest.getRequiredProperties();
532 for (String field : required) {
533 String defaultValue = null;
534 Object vertexProp = null;
535 defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
536 if (defaultValue != null) {
537 vertexProp = v.<Object>property(field).orElse(null);
538 if (vertexProp == null) {
539 v.property(field, defaultValue);
549 * Reflect dependent vertex.
552 * @param dependentObj the dependent obj
554 * @throws IllegalAccessException the illegal access exception
555 * @throws IllegalArgumentException the illegal argument exception
556 * @throws InvocationTargetException the invocation target exception
557 * @throws InstantiationException the instantiation exception
558 * @throws NoSuchMethodException the no such method exception
559 * @throws SecurityException the security exception
560 * @throws AAIException the AAI exception
561 * @throws UnsupportedEncodingException the unsupported encoding exception
562 * @throws AAIUnknownObjectException
564 private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
566 //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
567 //List<Vertex> items = p.getQuery().toList();
568 QueryBuilder<Vertex> query = this.engine.getQueryBuilder(v);
569 query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
570 query.createKeyQuery(dependentObj);
572 List<Vertex> items = query.toList();
574 Vertex dependentVertex = null;
575 if (items.size() == 1) {
576 dependentVertex = items.get(0);
577 this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
579 this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
580 dependentVertex = createNewVertex(dependentObj);
583 return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
588 * Reflect dependent vertex.
590 * @param parent the parent
591 * @param child the child
594 * @throws IllegalAccessException the illegal access exception
595 * @throws IllegalArgumentException the illegal argument exception
596 * @throws InvocationTargetException the invocation target exception
597 * @throws InstantiationException the instantiation exception
598 * @throws NoSuchMethodException the no such method exception
599 * @throws SecurityException the security exception
600 * @throws AAIException the AAI exception
601 * @throws UnsupportedEncodingException the unsupported encoding exception
602 * @throws AAIUnknownObjectException
604 private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
606 String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
607 if (parentUri != null) {
610 addUriIfNeeded(child, parentUri + uri);
612 processObject(obj, child, requestContext);
615 e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
617 String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
618 if (canBeLinked != null && canBeLinked.equals("true")) {
619 Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext));
620 boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
622 child.property(AAIProperties.LINKED, true);
625 edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
631 private SchemaVersion getVerForContext(String requestContext) {
632 Pattern pattern = Pattern.compile("v[0-9]+");
633 Matcher m = pattern.matcher(requestContext);
637 return new SchemaVersion(requestContext);
644 * @param vertices the vertices
646 * @param depth the depth
647 * @param cleanUp the clean up
648 * @return the introspector
649 * @throws AAIException the AAI exception
650 * @throws IllegalAccessException the illegal access exception
651 * @throws IllegalArgumentException the illegal argument exception
652 * @throws InvocationTargetException the invocation target exception
653 * @throws SecurityException the security exception
654 * @throws InstantiationException the instantiation exception
655 * @throws NoSuchMethodException the no such method exception
656 * @throws UnsupportedEncodingException the unsupported encoding exception
657 * @throws MalformedURLException the malformed URL exception
658 * @throws AAIUnknownObjectException
659 * @throws URISyntaxException
661 public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
662 final int internalDepth;
663 if (depth == Integer.MAX_VALUE) {
664 internalDepth = depth--;
666 internalDepth = depth;
668 StopWatch.conditionalStart();
669 if (vertices.size() > 1 && !obj.isContainer()) {
670 dbTimeMsecs += StopWatch.stopIfStarted();
671 throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
672 } else if (obj.isContainer()) {
674 String listProperty = null;
675 for (String property : obj.getProperties()) {
676 if (obj.isListType(property) && obj.isComplexGenericType(property)) {
677 listProperty = property;
681 final String propertyName = listProperty;
682 getList = (List)obj.getValue(listProperty);
684 /* This is an experimental multithreading experiment
687 ExecutorService pool = GetAllPool.getInstance().getPool();
689 List<Future<Object>> futures = new ArrayList<>();
691 QueryEngine tgEngine = this.engine.getQueryEngine();
692 for (Vertex v : vertices) {
694 AaiCallable<Object> task = new AaiCallable<Object>() {
696 public Object process() throws UnsupportedEncodingException, AAIException {
697 Set<Vertex> seen = new HashSet<>();
698 Introspector childObject;
700 childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
701 } catch (AAIUnknownObjectException e) {
704 Tree<Element> tree = tgEngine.findSubGraph(v, internalDepth, nodeOnly);
705 TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
707 dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
708 } catch (UnsupportedEncodingException e) {
710 } catch (AAIException e) {
713 return childObject.getUnderlyingObject();
714 //getList.add(childObject.getUnderlyingObject());
717 futures.add(pool.submit(task));
720 for (Future<Object> future : futures) {
722 getList.add(future.get());
723 } catch (ExecutionException e) {
724 dbTimeMsecs += StopWatch.stopIfStarted();
725 throw new AAIException("AAI_4000", e);
726 } catch (InterruptedException e) {
727 dbTimeMsecs += StopWatch.stopIfStarted();
728 throw new AAIException("AAI_4000", e);
731 } else if (vertices.size() == 1) {
732 Set<Vertex> seen = new HashSet<>();
733 Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly);
734 TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree);
735 dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
740 dbTimeMsecs += StopWatch.stopIfStarted();
749 * @param seen the seen
750 * @param depth the depth
751 * @param cleanUp the clean up
752 * @return the introspector
753 * @throws IllegalAccessException the illegal access exception
754 * @throws IllegalArgumentException the illegal argument exception
755 * @throws InvocationTargetException the invocation target exception
756 * @throws SecurityException the security exception
757 * @throws InstantiationException the instantiation exception
758 * @throws NoSuchMethodException the no such method exception
759 * @throws UnsupportedEncodingException the unsupported encoding exception
760 * @throws AAIException the AAI exception
761 * @throws MalformedURLException the malformed URL exception
762 * @throws AAIUnknownObjectException
763 * @throws URISyntaxException
765 private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
773 boolean modified = false;
774 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
775 List<Object> getList = null;
776 Vertex[] vertices = null;
778 if (!(obj.isComplexType(property) || obj.isListType(property))) {
779 this.copySimpleProperty(property, obj, v);
782 if (obj.isComplexType(property)) {
785 if (!property.equals("relationship-list") && depth >= 0) {
786 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
787 Object result = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp);
788 if (result != null) {
789 obj.setValue(property, argumentObject.getUnderlyingObject());
792 } else if (property.equals("relationship-list") && !nodeOnly){
793 /* relationships need to be handled correctly */
794 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
795 relationshipList = createRelationshipList(v, relationshipList, cleanUp);
796 if (relationshipList != null) {
798 obj.setValue(property, relationshipList.getUnderlyingObject());
803 } else if (obj.isListType(property)) {
805 if (property.equals("any")) {
808 String genericType = obj.getGenericTypeClass(property).getSimpleName();
809 if (obj.isComplexGenericType(property) && depth >= 0) {
810 final String childDbName = convertFromCamelCase(genericType);
811 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
815 rule = edgeRules.getRule(new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build());
816 } catch (EdgeRuleNotFoundException e) {
817 throw new NoEdgeRuleFoundException(e);
818 } catch (AmbiguousRuleChoiceException e) {
819 throw new MultipleEdgeRuleFoundException(e);
821 if (!rule.getContains().equals(AAIDirection.NONE.toString())) {
822 //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
823 Direction ruleDirection = rule.getDirection();
824 Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
825 List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
826 itr = verticesList.stream().filter(item -> {
827 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
830 getList = (List<Object>)obj.getValue(property);
834 while (itr.hasNext()) {
835 Vertex childVertex = itr.next();
836 if (!seen.contains(childVertex)) {
837 Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
839 Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
840 if (result != null) {
841 getList.add(argumentObject.getUnderlyingObject());
847 LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
850 if (processed == 0) {
851 //vertices were all seen, reset the list
858 } else if (obj.isSimpleGenericType(property)) {
859 List<Object> temp = this.engine.getListProperty(v, property);
861 getList = (List<Object>)obj.getValue(property);
862 getList.addAll(temp);
873 //no changes were made to this obj, discard the instance
877 this.enrichData(obj, v);
883 public Introspector getVertexProperties(Vertex v) throws AAIException, UnsupportedEncodingException {
884 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
885 if (nodeType == null) {
886 throw new AAIException("AAI_6143");
889 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
890 Set<Vertex> seen = new HashSet<>();
892 String cleanUp = "false";
893 boolean nodeOnly = true;
894 StopWatch.conditionalStart();
895 this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
896 dbTimeMsecs += StopWatch.stopIfStarted();
900 public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException {
901 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
902 if (nodeType == null) {
903 throw new AAIException("AAI_6143");
905 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
906 Set<Vertex> seen = new HashSet<>();
907 int depth = AAIProperties.MAXIMUM_DEPTH;
908 String cleanUp = "false";
909 boolean nodeOnly = false;
910 StopWatch.conditionalStart();
911 Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
912 TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
913 this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
914 dbTimeMsecs += StopWatch.stopIfStarted();
918 * Copy simple property.
920 * @param property the property
923 * @throws InstantiationException the instantiation exception
924 * @throws IllegalAccessException the illegal access exception
925 * @throws IllegalArgumentException the illegal argument exception
926 * @throws InvocationTargetException the invocation target exception
927 * @throws NoSuchMethodException the no such method exception
928 * @throws SecurityException the security exception
930 private void copySimpleProperty(String property, Introspector obj, Vertex v) {
932 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
933 String dbPropertyName = property;
935 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
936 dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
941 final Object temp = v.<Object>property(dbPropertyName).orElse(null);
943 obj.setValue(property, temp);
948 * Simple db to object.
952 * @throws InstantiationException the instantiation exception
953 * @throws IllegalAccessException the illegal access exception
954 * @throws IllegalArgumentException the illegal argument exception
955 * @throws InvocationTargetException the invocation target exception
956 * @throws NoSuchMethodException the no such method exception
957 * @throws SecurityException the security exception
959 private void simpleDbToObject (Introspector obj, Vertex v) {
960 for (String property : obj.getProperties()) {
963 if (!(obj.isComplexType(property) || obj.isListType(property))) {
964 this.copySimpleProperty(property, obj, v);
970 * Creates the relationship list.
974 * @param cleanUp the clean up
976 * @throws InstantiationException the instantiation exception
977 * @throws IllegalAccessException the illegal access exception
978 * @throws IllegalArgumentException the illegal argument exception
979 * @throws InvocationTargetException the invocation target exception
980 * @throws NoSuchMethodException the no such method exception
981 * @throws SecurityException the security exception
982 * @throws UnsupportedEncodingException the unsupported encoding exception
983 * @throws AAIException the AAI exception
984 * @throws MalformedURLException the malformed URL exception
985 * @throws URISyntaxException
987 private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
989 List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v);
991 List<Object> relationshipObjList = obj.getValue("relationship");
993 for (Vertex cousin : cousins) {
994 if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
995 List<Edge> edges = this.getEdgesBetween(EdgeType.COUSIN, v, cousin);
996 for (Edge e : edges) {
997 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
998 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, e);
999 if (result != null) {
1000 relationshipObjList.add(result);
1004 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1005 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
1006 if (result != null) {
1007 relationshipObjList.add(result);
1013 if (relationshipObjList.isEmpty()) {
1021 * Process edge relationship.
1023 * @param relationshipObj the relationship obj
1024 * @param edge the edge
1025 * @param cleanUp the clean up
1026 * @return the object
1027 * @throws InstantiationException the instantiation exception
1028 * @throws IllegalAccessException the illegal access exception
1029 * @throws IllegalArgumentException the illegal argument exception
1030 * @throws InvocationTargetException the invocation target exception
1031 * @throws NoSuchMethodException the no such method exception
1032 * @throws SecurityException the security exception
1033 * @throws UnsupportedEncodingException the unsupported encoding exception
1034 * @throws AAIException the AAI exception
1035 * @throws MalformedURLException the malformed URL exception
1036 * @throws AAIUnknownObjectException
1037 * @throws URISyntaxException
1039 private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp, Edge edge) throws UnsupportedEncodingException, AAIUnknownObjectException {
1042 //we must look up all parents in this case because we need to compute name-properties
1043 //we cannot used the cached aaiUri to perform this action currently
1044 Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp));
1045 //damaged vertex found, ignore
1046 if (!tuple.isPresent()) {
1049 List<Introspector> list = tuple.get().getValue1();
1050 URI uri = this.getURIFromList(list);
1052 URIToRelationshipObject uriParser = null;
1053 Introspector result = null;
1055 uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
1056 result = uriParser.getResult();
1057 } catch (AAIException | URISyntaxException e) {
1058 LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.get().getValue0().id().toString() + ": "
1059 + e.getMessage() + " " + LogFormatTools.getStackTop(e));
1060 if ("true".equals(cleanUp)) {
1061 this.deleteWithTraversal(tuple.get().getValue0());
1065 if (!list.isEmpty()) {
1066 this.addRelatedToProperty(result, list.get(0));
1069 if (edge != null && result.hasProperty("relationship-label")) {
1070 result.setValue("relationship-label", edge.label());
1073 return result.getUnderlyingObject();
1077 * Gets the URI for vertex.
1080 * @return the URI for vertex
1081 * @throws InstantiationException the instantiation exception
1082 * @throws IllegalAccessException the illegal access exception
1083 * @throws IllegalArgumentException the illegal argument exception
1084 * @throws InvocationTargetException the invocation target exception
1085 * @throws NoSuchMethodException the no such method exception
1086 * @throws SecurityException the security exception
1087 * @throws UnsupportedEncodingException the unsupported encoding exception
1088 * @throws AAIUnknownObjectException
1090 public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
1092 return getURIForVertex(v, false);
1095 public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
1096 URI uri = UriBuilder.fromPath("/unknown-uri").build();
1098 String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
1100 if (aaiUri != null && !overwrite) {
1101 uri = UriBuilder.fromPath(aaiUri).build();
1103 StopWatch.conditionalStart();
1104 Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(this.loader, v, false);
1105 dbTimeMsecs += StopWatch.stopIfStarted();
1106 if (tuple.isPresent()) {
1107 List<Introspector> list = tuple.get().getValue1();
1108 uri = this.getURIFromList(list);
1116 * Gets the URI from list.
1118 * @param list the list
1119 * @return the URI from list
1120 * @throws UnsupportedEncodingException the unsupported encoding exception
1122 private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
1124 StringBuilder sb = new StringBuilder();
1125 for (Introspector i : list) {
1126 sb.insert(0, i.getURI());
1129 uri = sb.toString();
1130 return UriBuilder.fromPath(uri).build();
1136 * @param start the start
1137 * @param removeDamaged the remove damaged
1138 * @return the parents
1139 * @throws InstantiationException the instantiation exception
1140 * @throws IllegalAccessException the illegal access exception
1141 * @throws IllegalArgumentException the illegal argument exception
1142 * @throws InvocationTargetException the invocation target exception
1143 * @throws NoSuchMethodException the no such method exception
1144 * @throws SecurityException the security exception
1145 * @throws AAIUnknownObjectException
1147 private Optional<Pair<Vertex, List<Introspector>>> getParents(Loader loader, Vertex start, boolean removeDamaged) {
1149 List<Vertex> results = this.engine.getQueryEngine().findParents(start);
1150 List<Introspector> objs = new ArrayList<>();
1151 boolean shortCircuit = false;
1152 for (Vertex v : results) {
1153 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1154 Introspector obj = null;
1155 //vertex on the other end of this edge is bad
1156 if (nodeType == null) {
1157 //log something here about what was found and that it was removed
1158 ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString());
1159 if (removeDamaged) {
1160 this.deleteWithTraversal(v);
1162 shortCircuit = true;
1165 obj = loader.introspectorFromName(nodeType);
1166 } catch (AAIUnknownObjectException e) {
1167 LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion());
1173 //can't make a valid path because we don't understand this object
1176 this.simpleDbToObject(obj, v);
1181 //stop processing and don't return anything for this bad vertex
1183 return Optional.empty();
1186 return Optional.of(new Pair<>(results.get(results.size()-1), objs));
1191 * @throws AAIUnknownObjectException
1192 * @throws IllegalArgumentException elated to property.
1194 * @param relationship the relationship
1195 * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
1197 public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
1198 String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
1199 List<Introspector> relatedToProperties = new ArrayList<>();
1201 if (nameProps != null) {
1202 String[] props = nameProps.split(",");
1203 for (String prop : props) {
1204 Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
1205 relatedTo.setValue("property-key", child.getDbName() + "." + prop);
1206 relatedTo.setValue("property-value", child.getValue(prop));
1207 relatedToProperties.add(relatedTo);
1211 if (!relatedToProperties.isEmpty()) {
1212 List relatedToList = (List)relationship.getValue("related-to-property");
1213 for (Introspector obj : relatedToProperties) {
1214 relatedToList.add(obj.getUnderlyingObject());
1223 * @param relationship the relationship
1224 * @param inputVertex the input vertex
1225 * @return true, if successful
1226 * @throws UnsupportedEncodingException the unsupported encoding exception
1227 * @throws AAIException the AAI exception
1229 public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1231 Vertex relatedVertex = null;
1232 StopWatch.conditionalStart();
1233 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1235 String label = null;
1236 if (relationship.hasProperty("relationship-label")) {
1237 label = relationship.getValue("relationship-label");
1240 List<Vertex> results = parser.getQueryBuilder().toList();
1241 if (results.isEmpty()) {
1242 dbTimeMsecs += StopWatch.stopIfStarted();
1243 AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
1244 e.getTemplateVars().add(parser.getResultType());
1245 e.getTemplateVars().add(parser.getUri().toString());
1248 //still an issue if there's more than one
1249 relatedVertex = results.get(0);
1252 if (relatedVertex != null) {
1256 e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1258 edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
1260 //attempted to link two vertexes already linked
1263 dbTimeMsecs += StopWatch.stopIfStarted();
1267 dbTimeMsecs += StopWatch.stopIfStarted();
1272 * Gets all the edges between of the type.
1274 * @param aVertex the out vertex
1275 * @param bVertex the in vertex
1276 * @return the edges between
1277 * @throws AAIException the AAI exception
1278 * @throws NoEdgeRuleFoundException
1280 private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
1282 List<Edge> result = new ArrayList<>();
1284 if (bVertex != null) {
1285 GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1286 findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
1287 if (EdgeType.TREE.equals(type)) {
1288 findEdgesBetween = findEdgesBetween
1291 __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
1292 __.has(EdgeField.PRIVATE.toString(), true)
1296 findEdgesBetween = findEdgesBetween
1297 .has(EdgeProperty.CONTAINS.toString(), "NONE")
1299 __.has(EdgeField.PRIVATE.toString(), true)
1302 findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
1303 result = findEdgesBetween.toList();
1309 * Gets all the edges between the vertexes with the label and type.
1311 * @param aVertex the out vertex
1312 * @param bVertex the in vertex
1314 * @return the edges between
1315 * @throws AAIException the AAI exception
1317 private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1319 List<Edge> result = new ArrayList<>();
1321 if (bVertex != null) {
1322 String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value();
1323 String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value();
1324 EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build();
1327 rule = edgeRules.getRule(q);
1328 } catch (EdgeRuleNotFoundException e) {
1329 throw new NoEdgeRuleFoundException(e);
1330 } catch (AmbiguousRuleChoiceException e) {
1331 throw new MultipleEdgeRuleFoundException(e);
1333 List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
1334 for (Edge edge : edges) {
1335 if (edge.label().equals(rule.getLabel())) {
1345 * Gets the edge between with the label and edge type.
1347 * @param aVertex the out vertex
1348 * @param bVertex the in vertex
1350 * @return the edge between
1351 * @throws AAIException the AAI exception
1352 * @throws NoEdgeRuleFoundException
1354 public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1356 StopWatch.conditionalStart();
1357 if (bVertex != null) {
1359 List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex, label);
1361 if (!edges.isEmpty()) {
1362 dbTimeMsecs += StopWatch.stopIfStarted();
1363 return edges.get(0);
1367 dbTimeMsecs += StopWatch.stopIfStarted();
1370 public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
1371 return this.getEdgeBetween(type, aVertex, bVertex, null);
1378 * @param relationship the relationship
1379 * @param inputVertex the input vertex
1380 * @return true, if successful
1381 * @throws UnsupportedEncodingException the unsupported encoding exception
1382 * @throws AAIException the AAI exception
1384 public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1386 Vertex relatedVertex = null;
1387 StopWatch.conditionalStart();
1388 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1390 List<Vertex> results = parser.getQueryBuilder().toList();
1392 String label = null;
1393 if (relationship.hasProperty("relationship-label")) {
1394 label = relationship.getValue("relationship-label");
1397 if (results.isEmpty()) {
1398 dbTimeMsecs += StopWatch.stopIfStarted();
1402 relatedVertex = results.get(0);
1405 edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1406 } catch (NoEdgeRuleFoundException e) {
1407 dbTimeMsecs += StopWatch.stopIfStarted();
1408 throw new AAIException("AAI_6129", e);
1412 dbTimeMsecs += StopWatch.stopIfStarted();
1415 dbTimeMsecs += StopWatch.stopIfStarted();
1422 * Delete items with traversal.
1424 * @param vertexes the vertexes
1425 * @throws IllegalStateException the illegal state exception
1427 public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
1429 for (Vertex v : vertexes) {
1430 LOGGER.debug("About to delete the vertex with id: " + v.id());
1431 deleteWithTraversal(v);
1437 * Delete with traversal.
1439 * @param startVertex the start vertex
1441 public void deleteWithTraversal(Vertex startVertex) {
1442 StopWatch.conditionalStart();
1443 List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
1445 for (Vertex v : results) {
1446 LOGGER.warn("Removing vertex " + v.id().toString());
1450 dbTimeMsecs += StopWatch.stopIfStarted();
1457 * @param resourceVersion the resource version
1458 * @throws IllegalArgumentException the illegal argument exception
1459 * @throws AAIException the AAI exception
1460 * @throws InterruptedException the interrupted exception
1462 public void delete(Vertex v, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
1464 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1466 * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain
1467 * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted
1468 * So its better to make these in 2 steps
1470 if(result && !deletableVertices.isEmpty()){
1471 result = verifyPreventDeleteSemantics(deletableVertices);
1476 deleteWithTraversal(v);
1477 } catch (IllegalStateException e) {
1478 throw new AAIException("AAI_6110", e);
1490 * @param resourceVersion the resource version
1491 * @throws IllegalArgumentException the illegal argument exception
1492 * @throws AAIException the AAI exception
1493 * @throws InterruptedException the interrupted exception
1495 public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
1497 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1502 deleteWithTraversal(v);
1503 } catch (IllegalStateException e) {
1504 throw new AAIException("AAI_6110", e);
1511 * Verify delete semantics.
1513 * @param vertex the vertex
1514 * @param resourceVersion the resource version
1515 * @return true, if successful
1516 * @throws AAIException the AAI exception
1518 private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
1519 boolean result = true;
1520 String nodeType = "";
1521 String errorDetail = " unknown delete semantic found";
1522 String aaiExceptionCode = "";
1523 nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1524 if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
1526 List<Vertex> vertices = new ArrayList<Vertex>();
1527 vertices.add(vertex);
1528 result = verifyPreventDeleteSemantics(vertices);
1534 * Verify Prevent delete semantics.
1535 * @param vertices the list of vertices
1536 * @return true, if successful
1537 * @throws AAIException the AAI exception
1539 private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException {
1540 boolean result = true;
1541 String nodeType = "";
1542 String errorDetail = " unknown delete semantic found";
1543 String aaiExceptionCode = "";
1545 StopWatch.conditionalStart();
1547 * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition
1548 * If yes - that should prevent the deletion of the vertex
1549 * Dedup makes sure we dont capture the prevent-delete vertices twice
1550 * The prevent-delete vertices are stored so that the error message displays what prevents the delete
1553 List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices).
1554 union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE),
1555 __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE))
1558 dbTimeMsecs += StopWatch.stopIfStarted();
1559 if (!preventDeleteVertices.isEmpty()) {
1560 aaiExceptionCode = "AAI_6110";
1561 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);
1565 throw new AAIException(aaiExceptionCode, errorDetail);
1571 * Verify resource version.
1573 * @param action the action
1574 * @param nodeType the node type
1575 * @param currentResourceVersion the current resource version
1576 * @param resourceVersion the resource version
1577 * @param uri the uri
1578 * @return true, if successful
1579 * @throws AAIException the AAI exception
1581 public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
1582 String enabled = "";
1583 String errorDetail = "";
1584 String aaiExceptionCode = "";
1585 if (currentResourceVersion == null) {
1586 currentResourceVersion = "";
1589 if (resourceVersion == null) {
1590 resourceVersion = "";
1593 enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
1594 } catch (AAIException e) {
1595 ErrorLogHelper.logException(e);
1597 if (enabled.equals("true")) {
1598 if (!currentResourceVersion.equals(resourceVersion)) {
1599 if (action.equals("create") && !resourceVersion.equals("")) {
1600 errorDetail = "resource-version passed for " + action + " of " + uri;
1601 aaiExceptionCode = "AAI_6135";
1602 } else if (resourceVersion.equals("")) {
1603 errorDetail = "resource-version not passed for " + action + " of " + uri;
1604 aaiExceptionCode = "AAI_6130";
1606 errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
1607 aaiExceptionCode = "AAI_6131";
1610 throw new AAIException(aaiExceptionCode, errorDetail);
1618 * Convert from camel case.
1620 * @param name the name
1621 * @return the string
1623 private String convertFromCamelCase (String name) {
1625 result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
1627 NamingExceptions exceptions = NamingExceptions.getInstance();
1628 result = exceptions.getDBName(result);
1633 private boolean canModify(Introspector obj, String propName, String requestContext) {
1634 final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
1635 if (readOnly != null) {
1636 final String[] items = readOnly.split(",");
1637 for (String item : items) {
1638 if (requestContext.equals(item)) {
1646 private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
1648 SideEffectRunner runner = new SideEffectRunner
1649 .Builder(this.engine, this).addSideEffect(DataCopy.class).addSideEffect(PrivateEdge.class).build();
1651 runner.execute(obj, self);
1654 private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
1656 SideEffectRunner runner = new SideEffectRunner
1657 .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
1659 runner.execute(obj, self);
1662 private void enrichData(Introspector obj, Vertex self) throws AAIException {
1664 SideEffectRunner runner = new SideEffectRunner
1665 .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
1667 runner.execute(obj, self);
1670 public double getDBTimeMsecs() {
1671 return (dbTimeMsecs);
1675 * Db to object With Filters
1676 * This is for a one-time run with Tenant Isloation to only filter relationships
1677 * TODO: Chnage the original dbToObject to take filter parent/cousins
1679 * @param obj the obj
1680 * @param v the vertex from the graph
1681 * @param depth the depth
1682 * @param nodeOnly specify if to exclude relationships or not
1683 * @param filterCousinNodes
1684 * @return the introspector
1685 * @throws AAIException the AAI exception
1686 * @throws IllegalAccessException the illegal access exception
1687 * @throws IllegalArgumentException the illegal argument exception
1688 * @throws InvocationTargetException the invocation target exception
1689 * @throws SecurityException the security exception
1690 * @throws InstantiationException the instantiation exception
1691 * @throws NoSuchMethodException the no such method exception
1692 * @throws UnsupportedEncodingException the unsupported encoding exception
1693 * @throws MalformedURLException the malformed URL exception
1694 * @throws AAIUnknownObjectException
1695 * @throws URISyntaxException
1697 //TODO - See if you can merge the 2 dbToObjectWithFilters
1698 public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, List<String> filterCousinNodes, List<String> filterParentNodes) throws AAIException, UnsupportedEncodingException {
1699 String cleanUp = "false";
1705 boolean modified = false;
1706 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
1707 List<Object> getList = null;
1708 Vertex[] vertices = null;
1710 if (!(obj.isComplexType(property) || obj.isListType(property))) {
1711 this.copySimpleProperty(property, obj, v);
1714 if (obj.isComplexType(property)) {
1715 /* container case */
1717 if (!property.equals("relationship-list") && depth >= 0) {
1718 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
1719 Object result = dbToObjectWithFilters(argumentObject, v, seen, depth+1, nodeOnly, filterCousinNodes, filterParentNodes);
1720 if (result != null) {
1721 obj.setValue(property, argumentObject.getUnderlyingObject());
1724 } else if (property.equals("relationship-list") && !nodeOnly){
1725 /* relationships need to be handled correctly */
1726 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
1727 relationshipList = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
1728 if (relationshipList != null) {
1730 obj.setValue(property, relationshipList.getUnderlyingObject());
1735 } else if (obj.isListType(property)) {
1737 if (property.equals("any")) {
1740 String genericType = obj.getGenericTypeClass(property).getSimpleName();
1741 if (obj.isComplexGenericType(property) && depth >= 0) {
1742 final String childDbName = convertFromCamelCase(genericType);
1743 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1746 boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains);
1748 EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build();
1751 rule = edgeRules.getRule(q);
1752 } catch (EdgeRuleNotFoundException e) {
1753 throw new NoEdgeRuleFoundException(e);
1754 } catch (AmbiguousRuleChoiceException e) {
1755 throw new MultipleEdgeRuleFoundException(e);
1757 if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
1758 //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
1759 Direction ruleDirection = rule.getDirection();
1760 Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
1761 List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
1762 itr = verticesList.stream().filter(item -> {
1763 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
1765 if (itr.hasNext()) {
1766 getList = (List<Object>)obj.getValue(property);
1770 while (itr.hasNext()) {
1771 Vertex childVertex = itr.next();
1772 if (!seen.contains(childVertex)) {
1773 Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
1775 Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes);
1776 if (result != null) {
1777 getList.add(argumentObject.getUnderlyingObject());
1783 LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
1786 if (processed == 0) {
1787 //vertices were all seen, reset the list
1790 if (processed > 0) {
1794 } else if (obj.isSimpleGenericType(property)) {
1795 List<Object> temp = this.engine.getListProperty(v, property);
1797 getList = (List<Object>)obj.getValue(property);
1798 getList.addAll(temp);
1809 //no changes were made to this obj, discard the instance
1813 this.enrichData(obj, v);
1819 * Creates the relationship list with the filtered node types.
1822 * @param obj the obj
1823 * @param cleanUp the clean up
1824 * @return the object
1825 * @throws InstantiationException the instantiation exception
1826 * @throws IllegalAccessException the illegal access exception
1827 * @throws IllegalArgumentException the illegal argument exception
1828 * @throws InvocationTargetException the invocation target exception
1829 * @throws NoSuchMethodException the no such method exception
1830 * @throws SecurityException the security exception
1831 * @throws UnsupportedEncodingException the unsupported encoding exception
1832 * @throws AAIException the AAI exception
1833 * @throws MalformedURLException the malformed URL exception
1834 * @throws URISyntaxException
1836 private Introspector createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
1837 List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
1839 Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
1840 String node = (String)item.property(AAIProperties.NODE_TYPE).orElse("");
1841 return filterNodes.parallelStream().anyMatch(node::contains);
1845 List<Vertex> cousins = (List<Vertex>)IteratorUtils.toList(cousinVertices);
1847 //items.parallelStream().anyMatch(inputStr::contains)
1848 List<Object> relationshipObjList = obj.getValue("relationship");
1849 for (Vertex cousin : cousins) {
1851 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1852 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
1853 if (result != null) {
1854 relationshipObjList.add(result);
1860 if (relationshipObjList.isEmpty()) {