2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 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 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22 package org.onap.aai.serialization.db;
25 import com.att.eelf.configuration.EELFLogger;
26 import com.att.eelf.configuration.EELFManager;
27 import com.google.common.base.CaseFormat;
28 import com.thinkaurelius.titan.core.SchemaViolationException;
29 import org.apache.commons.collections.IteratorUtils;
30 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
31 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
32 import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
33 import org.apache.tinkerpop.gremlin.structure.*;
34 import org.javatuples.Pair;
35 import org.javatuples.Triplet;
36 import org.onap.aai.db.props.AAIProperties;
37 import org.onap.aai.exceptions.AAIException;
38 import org.onap.aai.introspection.*;
39 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
40 import org.onap.aai.introspection.sideeffect.DataCopy;
41 import org.onap.aai.introspection.sideeffect.DataLinkReader;
42 import org.onap.aai.introspection.sideeffect.DataLinkWriter;
43 import org.onap.aai.introspection.sideeffect.SideEffectRunner;
44 import org.onap.aai.logging.ErrorLogHelper;
45 import org.onap.aai.logging.LogFormatTools;
46 import org.onap.aai.parsers.query.QueryParser;
47 import org.onap.aai.parsers.uri.URIParser;
48 import org.onap.aai.parsers.uri.URIToRelationshipObject;
49 import org.onap.aai.query.builder.QueryBuilder;
50 import org.onap.aai.schema.enums.ObjectMetadata;
51 import org.onap.aai.schema.enums.PropertyMetadata;
52 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
53 import org.onap.aai.serialization.db.util.VersionChecker;
54 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
55 import org.onap.aai.serialization.tinkerpop.TreeBackedVertex;
56 import org.onap.aai.util.AAIApiServerURLBase;
57 import org.onap.aai.util.AAIConfig;
58 import org.onap.aai.util.AAIConstants;
59 import org.onap.aai.workarounds.NamingExceptions;
60 import org.onap.aai.logging.StopWatch;
62 import javax.ws.rs.core.UriBuilder;
63 import java.io.UnsupportedEncodingException;
64 import java.lang.reflect.Array;
65 import java.lang.reflect.InvocationTargetException;
66 import java.net.MalformedURLException;
68 import java.net.URISyntaxException;
70 import java.util.concurrent.Callable;
71 import java.util.concurrent.ExecutionException;
72 import java.util.concurrent.ExecutorService;
73 import java.util.concurrent.Future;
74 import java.util.regex.Matcher;
75 import java.util.regex.Pattern;
77 public class DBSerializer {
79 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
81 private final TransactionalGraphEngine engine;
82 private final String sourceOfTruth;
83 private final ModelType introspectionType;
84 private final Version version;
85 private final Loader latestLoader;
86 private final EdgeRules edgeRules = EdgeRules.getInstance();
87 private final Loader loader;
88 private final String baseURL;
89 private double dbTimeMsecs = 0;
91 * Instantiates a new DB serializer.
93 * @param version the version
94 * @param engine the engine
96 * @param introspectionType the introspection type
97 * @param sourceOfTruth the source of truth
98 * @param llBuilder the ll builder
99 * @throws AAIException
101 public DBSerializer(Version version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
102 this.engine = engine;
103 this.sourceOfTruth = sourceOfTruth;
104 this.introspectionType = introspectionType;
105 this.latestLoader = LoaderFactory.createLoaderForVersion(introspectionType, AAIProperties.LATEST);
106 this.version = version;
107 this.loader = LoaderFactory.createLoaderForVersion(introspectionType, version);
108 this.baseURL = AAIApiServerURLBase.get(version);
112 * Touch standard vertex properties.
115 * @param isNewVertex the is new vertex
117 public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
119 String timeNowInSec = Long.toString(System.currentTimeMillis());
121 v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
122 v.property(AAIProperties.CREATED_TS, timeNowInSec);
123 v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
125 v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec );
126 v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
127 v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
131 private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) {
133 v.property(AAIProperties.NODE_TYPE, nodeType);
134 touchStandardVertexProperties(v, isNewVertex);
141 * Creates the new vertex.
143 * @param wrappedObject the wrapped object
145 * @throws UnsupportedEncodingException the unsupported encoding exception
146 * @throws AAIException the AAI exception
148 public Vertex createNewVertex(Introspector wrappedObject) {
151 StopWatch.conditionalStart();
152 v = this.engine.tx().addVertex();
153 touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
156 dbTimeMsecs += StopWatch.stopIfStarted();
164 * @param className the class name
168 * Removes the classpath from a class name
170 public String trimClassName (String className) {
171 String returnValue = "";
173 if (className.lastIndexOf('.') == -1) {
176 returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
186 * @param uriQuery the uri query
187 * @param identifier the identifier
188 * @throws SecurityException the security exception
189 * @throws IllegalAccessException the illegal access exception
190 * @throws IllegalArgumentException the illegal argument exception
191 * @throws InvocationTargetException the invocation target exception
192 * @throws InstantiationException the instantiation exception
193 * @throws InterruptedException the interrupted exception
194 * @throws NoSuchMethodException the no such method exception
195 * @throws AAIException the AAI exception
196 * @throws UnsupportedEncodingException the unsupported encoding exception
197 * @throws AAIUnknownObjectException
199 public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
200 StopWatch.conditionalStart();
202 if (uriQuery.isDependent()) {
203 //try to find the parent
204 List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
205 if (!vertices.isEmpty()) {
206 Vertex parent = vertices.get(0);
207 this.reflectDependentVertex(parent, v, obj, requestContext);
209 dbTimeMsecs += StopWatch.stopIfStarted();
210 throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
213 serializeSingleVertex(v, obj, requestContext);
216 } catch (SchemaViolationException e) {
217 dbTimeMsecs += StopWatch.stopIfStarted();
218 throw new AAIException("AAI_6117", e);
220 dbTimeMsecs += StopWatch.stopIfStarted();
223 public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
224 StopWatch.conditionalStart();
226 boolean isTopLevel = obj.isTopLevel();
228 v.property(AAIProperties.AAI_URI, obj.getURI());
231 processObject(obj, v, requestContext);
233 URI uri = this.getURIForVertex(v);
234 URIParser parser = new URIParser(this.loader, uri);
235 if (parser.validate()) {
236 VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
237 if (!uriProp.isPresent() || uriProp.isPresent() && !uriProp.value().equals(uri.toString())) {
238 v.property(AAIProperties.AAI_URI, uri.toString());
242 } catch (SchemaViolationException e) {
243 throw new AAIException("AAI_6117", e);
246 dbTimeMsecs += StopWatch.stopIfStarted();
253 * @param <T> the generic type
257 * @throws IllegalAccessException the illegal access exception
258 * @throws IllegalArgumentException the illegal argument exception
259 * @throws InvocationTargetException the invocation target exception
260 * @throws InstantiationException the instantiation exception
261 * @throws NoSuchMethodException the no such method exception
262 * @throws SecurityException the security exception
263 * @throws AAIException the AAI exception
264 * @throws UnsupportedEncodingException the unsupported encoding exception
265 * @throws AAIUnknownObjectException
268 * Helper method for reflectToDb
269 * Handles all the property setting
271 private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
272 Set<String> properties = new LinkedHashSet<>(obj.getProperties());
273 properties.remove(AAIProperties.RESOURCE_VERSION);
274 List<Vertex> dependentVertexes = new ArrayList<>();
275 List<Vertex> processedVertexes = new ArrayList<>();
276 boolean isComplexType = false;
277 boolean isListType = false;
278 if (!obj.isContainer()) {
279 this.touchStandardVertexProperties(obj.getDbName(), v, false);
281 this.executePreSideEffects(obj, v);
282 for (String property : properties) {
284 final String propertyType;
285 propertyType = obj.getType(property);
286 isComplexType = obj.isComplexType(property);
287 isListType = obj.isListType(property);
288 value = obj.getValue(property);
290 if (!(isComplexType || isListType)) {
291 boolean canModify = this.canModify(obj, property, requestContext);
294 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
295 String dbProperty = property;
296 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
297 dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
299 if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
300 //data linked properties are ephemeral
301 //they are populated dynamically on GETs
305 if (!value.equals(v.property(dbProperty).orElse(null))) {
306 if (propertyType.toLowerCase().contains(".long")) {
307 v.property(dbProperty, new Integer(((Long)value).toString()));
309 v.property(dbProperty, value);
313 v.property(dbProperty).remove();
316 } else if (isListType) {
317 List<Object> list = (List<Object>)value;
318 if (obj.isComplexGenericType(property)) {
320 for (Object o : list) {
321 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
322 child.setURIChain(obj.getURI());
323 processedVertexes.add(reflectDependentVertex(v, child, requestContext));
328 engine.setListProperty(v, property, list);
331 //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
332 if (value != null) { //effectively ignore complex properties not included in the object we're processing
333 if (value.getClass().isArray()) {
335 int length = Array.getLength(value);
336 for (int i = 0; i < length; i ++) {
337 Object arrayElement = Array.get(value, i);
338 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
339 child.setURIChain(obj.getURI());
340 processedVertexes.add(reflectDependentVertex(v, child, requestContext));
343 } else if (!property.equals("relationship-list")) {
345 Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
346 if (introspector.isContainer()) {
347 dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
348 introspector.setURIChain(obj.getURI());
350 processedVertexes.addAll(processObject(introspector, v, requestContext));
353 dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
354 processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
357 } else if (property.equals("relationship-list")) {
358 handleRelationships(obj, v);
363 this.writeThroughDefaults(v, obj);
364 /* handle those vertexes not touched */
365 for (Vertex toBeRemoved : processedVertexes) {
366 dependentVertexes.remove(toBeRemoved);
368 this.deleteItemsWithTraversal(dependentVertexes);
370 this.executePostSideEffects(obj, v);
371 return processedVertexes;
375 * Handle relationships.
378 * @param vertex the vertex
379 * @throws SecurityException the security exception
380 * @throws IllegalAccessException the illegal access exception
381 * @throws IllegalArgumentException the illegal argument exception
382 * @throws InvocationTargetException the invocation target exception
383 * @throws UnsupportedEncodingException the unsupported encoding exception
384 * @throws AAIException the AAI exception
387 * Handles the explicit relationships defined for an obj
389 private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
393 Introspector wrappedRl = obj.getWrappedValue("relationship-list");
394 processRelationshipList(wrappedRl, vertex);
401 * Process relationship list.
403 * @param wrapped the wrapped
405 * @throws UnsupportedEncodingException the unsupported encoding exception
406 * @throws AAIException the AAI exception
408 private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
410 List<Object> relationships = (List<Object>)wrapped.getValue("relationship");
412 List<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
413 List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
415 for (Object relationship : relationships) {
417 Vertex cousinVertex = null;
419 Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
420 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
422 if (wrappedRel.hasProperty("relationship-label")) {
423 label = wrappedRel.getValue("relationship-label");
426 List<Vertex> results = parser.getQueryBuilder().toList();
427 if (results.isEmpty()) {
428 final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
429 ex.getTemplateVars().add(parser.getResultType());
430 ex.getTemplateVars().add(parser.getUri().toString());
433 //still an issue if there's more than one
434 cousinVertex = results.get(0);
437 if (cousinVertex != null) {
439 if (!edgeRules.hasEdgeRule(v, cousinVertex, label)) {
440 throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + v.property(AAIProperties.NODE_TYPE).value().toString() + ", "
441 + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString() + (label != null ? (" with label " + label):"") +".");
442 } else if (edgeRules.hasTreeEdgeRule(v, cousinVertex) && !edgeRules.hasCousinEdgeRule(v, cousinVertex, label)) {
443 throw new AAIException("AAI_6145");
446 e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
449 addEdges.add(new Triplet<>(v, cousinVertex, label));
451 existingEdges.remove(e);
456 for (Edge edge : existingEdges) {
459 for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
461 edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2());
462 } catch (NoEdgeRuleFoundException e) {
463 throw new AAIException("AAI_6129", e);
470 * Write through defaults.
474 * @throws AAIUnknownObjectException
476 private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
477 Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
478 if (latest != null) {
479 Set<String> required = latest.getRequiredProperties();
481 for (String field : required) {
482 String defaultValue = null;
483 Object vertexProp = null;
484 defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
485 if (defaultValue != null) {
486 vertexProp = v.<Object>property(field).orElse(null);
487 if (vertexProp == null) {
488 v.property(field, defaultValue);
498 * Reflect dependent vertex.
501 * @param dependentObj the dependent obj
503 * @throws IllegalAccessException the illegal access exception
504 * @throws IllegalArgumentException the illegal argument exception
505 * @throws InvocationTargetException the invocation target exception
506 * @throws InstantiationException the instantiation exception
507 * @throws NoSuchMethodException the no such method exception
508 * @throws SecurityException the security exception
509 * @throws AAIException the AAI exception
510 * @throws UnsupportedEncodingException the unsupported encoding exception
511 * @throws AAIUnknownObjectException
513 private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
515 //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
516 //List<Vertex> items = p.getQuery().toList();
517 QueryBuilder<Vertex> query = this.engine.getQueryBuilder(v);
518 query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
519 query.createKeyQuery(dependentObj);
521 List<Vertex> items = query.toList();
523 Vertex dependentVertex = null;
524 if (items.size() == 1) {
525 dependentVertex = items.get(0);
526 this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
528 this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
529 dependentVertex = createNewVertex(dependentObj);
532 return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
537 * Reflect dependent vertex.
539 * @param parent the parent
540 * @param child the child
543 * @throws IllegalAccessException the illegal access exception
544 * @throws IllegalArgumentException the illegal argument exception
545 * @throws InvocationTargetException the invocation target exception
546 * @throws InstantiationException the instantiation exception
547 * @throws NoSuchMethodException the no such method exception
548 * @throws SecurityException the security exception
549 * @throws AAIException the AAI exception
550 * @throws UnsupportedEncodingException the unsupported encoding exception
551 * @throws AAIUnknownObjectException
553 private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
555 String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
556 if (parentUri != null) {
559 child.property(AAIProperties.AAI_URI, parentUri + uri);
561 processObject(obj, child, requestContext);
564 e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
566 String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
567 if (canBeLinked != null && canBeLinked.equals("true")) {
568 Loader ldrForCntxt = LoaderFactory.createLoaderForVersion(introspectionType, getVerForContext(requestContext));
569 boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
571 child.property(AAIProperties.LINKED, true);
574 edgeRules.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
580 private Version getVerForContext(String requestContext) {
581 Pattern pattern = Pattern.compile("v[0-9]+");
582 Matcher m = pattern.matcher(requestContext);
586 return Version.valueOf(requestContext);
593 * @param vertices the vertices
595 * @param depth the depth
596 * @param cleanUp the clean up
597 * @return the introspector
598 * @throws AAIException the AAI exception
599 * @throws IllegalAccessException the illegal access exception
600 * @throws IllegalArgumentException the illegal argument exception
601 * @throws InvocationTargetException the invocation target exception
602 * @throws SecurityException the security exception
603 * @throws InstantiationException the instantiation exception
604 * @throws NoSuchMethodException the no such method exception
605 * @throws UnsupportedEncodingException the unsupported encoding exception
606 * @throws MalformedURLException the malformed URL exception
607 * @throws AAIUnknownObjectException
608 * @throws URISyntaxException
610 public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
611 final int internalDepth;
612 if (depth == Integer.MAX_VALUE) {
613 internalDepth = depth--;
615 internalDepth = depth;
617 StopWatch.conditionalStart();
618 if (vertices.size() > 1 && !obj.isContainer()) {
619 dbTimeMsecs += StopWatch.stopIfStarted();
620 throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
621 } else if (obj.isContainer()) {
623 String listProperty = null;
624 for (String property : obj.getProperties()) {
625 if (obj.isListType(property) && obj.isComplexGenericType(property)) {
626 listProperty = property;
630 final String propertyName = listProperty;
631 getList = (List)obj.getValue(listProperty);
633 /* This is an experimental multithreading experiment
636 ExecutorService pool = GetAllPool.getInstance().getPool();
638 List<Future<Object>> futures = new ArrayList<>();
641 for (Vertex v : vertices) {
642 Callable<Object> task = () -> {
643 Set<Vertex> seen = new HashSet<>();
644 Introspector childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
645 Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, internalDepth, nodeOnly);
646 TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
647 dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
648 return childObject.getUnderlyingObject();
649 //getList.add(childObject.getUnderlyingObject());
651 futures.add(pool.submit(task));
654 for (Future<Object> future : futures) {
656 getList.add(future.get());
657 } catch (ExecutionException e) {
658 dbTimeMsecs += StopWatch.stopIfStarted();
659 throw new AAIException("AAI_4000", e);
660 } catch (InterruptedException e) {
661 dbTimeMsecs += StopWatch.stopIfStarted();
662 throw new AAIException("AAI_4000", e);
665 } else if (vertices.size() == 1) {
666 Set<Vertex> seen = new HashSet<>();
667 Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly);
668 TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree);
669 dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
674 dbTimeMsecs += StopWatch.stopIfStarted();
683 * @param seen the seen
684 * @param depth the depth
685 * @param cleanUp the clean up
686 * @return the introspector
687 * @throws IllegalAccessException the illegal access exception
688 * @throws IllegalArgumentException the illegal argument exception
689 * @throws InvocationTargetException the invocation target exception
690 * @throws SecurityException the security exception
691 * @throws InstantiationException the instantiation exception
692 * @throws NoSuchMethodException the no such method exception
693 * @throws UnsupportedEncodingException the unsupported encoding exception
694 * @throws AAIException the AAI exception
695 * @throws MalformedURLException the malformed URL exception
696 * @throws AAIUnknownObjectException
697 * @throws URISyntaxException
699 private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
707 boolean modified = false;
708 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
709 List<Object> getList = null;
710 Vertex[] vertices = null;
712 if (!(obj.isComplexType(property) || obj.isListType(property))) {
713 this.copySimpleProperty(property, obj, v);
716 if (obj.isComplexType(property)) {
719 if (!property.equals("relationship-list") && depth >= 0) {
720 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
721 Object result = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp);
722 if (result != null) {
723 obj.setValue(property, argumentObject.getUnderlyingObject());
726 } else if (property.equals("relationship-list") && !nodeOnly){
727 /* relationships need to be handled correctly */
728 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
729 relationshipList = createRelationshipList(v, relationshipList, cleanUp);
730 if (relationshipList != null) {
732 obj.setValue(property, relationshipList.getUnderlyingObject());
737 } else if (obj.isListType(property)) {
739 if (property.equals("any")) {
742 String genericType = obj.getGenericTypeClass(property).getSimpleName();
743 if (obj.isComplexGenericType(property) && depth >= 0) {
744 final String childDbName = convertFromCamelCase(genericType);
745 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
748 rule = edgeRules.getEdgeRule(EdgeType.TREE, vType, childDbName);
749 if (!rule.getContains().equals(AAIDirection.NONE.toString())) {
750 //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
751 Direction ruleDirection = rule.getDirection();
752 Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
753 List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
754 itr = verticesList.stream().filter(item -> {
755 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
758 getList = (List<Object>)obj.getValue(property);
762 while (itr.hasNext()) {
763 Vertex childVertex = itr.next();
764 if (!seen.contains(childVertex)) {
765 Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
767 Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
768 if (result != null) {
769 getList.add(argumentObject.getUnderlyingObject());
775 LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
778 if (processed == 0) {
779 //vertices were all seen, reset the list
786 } else if (obj.isSimpleGenericType(property)) {
787 List<Object> temp = this.engine.getListProperty(v, property);
789 getList = (List<Object>)obj.getValue(property);
790 getList.addAll(temp);
801 //no changes were made to this obj, discard the instance
805 this.enrichData(obj, v);
811 public Introspector getVertexProperties(Vertex v) throws AAIException, UnsupportedEncodingException {
812 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
813 if (nodeType == null) {
814 throw new AAIException("AAI_6143");
817 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
818 Set<Vertex> seen = new HashSet<>();
820 String cleanUp = "false";
821 boolean nodeOnly = true;
822 StopWatch.conditionalStart();
823 this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
824 dbTimeMsecs += StopWatch.stopIfStarted();
828 public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException {
829 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
830 if (nodeType == null) {
831 throw new AAIException("AAI_6143");
833 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
834 Set<Vertex> seen = new HashSet<>();
835 int depth = AAIProperties.MAXIMUM_DEPTH;
836 String cleanUp = "false";
837 boolean nodeOnly = false;
838 StopWatch.conditionalStart();
839 Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
840 TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
841 this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
842 dbTimeMsecs += StopWatch.stopIfStarted();
846 * Copy simple property.
848 * @param property the property
851 * @throws InstantiationException the instantiation exception
852 * @throws IllegalAccessException the illegal access exception
853 * @throws IllegalArgumentException the illegal argument exception
854 * @throws InvocationTargetException the invocation target exception
855 * @throws NoSuchMethodException the no such method exception
856 * @throws SecurityException the security exception
858 private void copySimpleProperty(String property, Introspector obj, Vertex v) {
859 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
860 String dbPropertyName = property;
861 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
862 dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
864 final Object temp = v.<Object>property(dbPropertyName).orElse(null);
867 obj.setValue(property, temp);
872 * Simple db to object.
876 * @throws InstantiationException the instantiation exception
877 * @throws IllegalAccessException the illegal access exception
878 * @throws IllegalArgumentException the illegal argument exception
879 * @throws InvocationTargetException the invocation target exception
880 * @throws NoSuchMethodException the no such method exception
881 * @throws SecurityException the security exception
883 private void simpleDbToObject (Introspector obj, Vertex v) {
884 for (String property : obj.getProperties()) {
887 if (!(obj.isComplexType(property) || obj.isListType(property))) {
888 this.copySimpleProperty(property, obj, v);
894 * Creates the relationship list.
898 * @param cleanUp the clean up
900 * @throws InstantiationException the instantiation exception
901 * @throws IllegalAccessException the illegal access exception
902 * @throws IllegalArgumentException the illegal argument exception
903 * @throws InvocationTargetException the invocation target exception
904 * @throws NoSuchMethodException the no such method exception
905 * @throws SecurityException the security exception
906 * @throws UnsupportedEncodingException the unsupported encoding exception
907 * @throws AAIException the AAI exception
908 * @throws MalformedURLException the malformed URL exception
909 * @throws URISyntaxException
911 private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
913 List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v);
915 List<Object> relationshipObjList = obj.getValue("relationship");
917 for (Vertex cousin : cousins) {
918 if (VersionChecker.apiVersionNeedsEdgeLabel(obj.getVersion())) {
919 List<Edge> edges = this.getEdgesBetween(EdgeType.COUSIN, v, cousin);
920 for (Edge e : edges) {
921 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
922 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, e);
923 if (result != null) {
924 relationshipObjList.add(result);
928 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
929 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
930 if (result != null) {
931 relationshipObjList.add(result);
937 if (relationshipObjList.isEmpty()) {
945 * Process edge relationship.
947 * @param relationshipObj the relationship obj
948 * @param edge the edge
949 * @param direction the direction
950 * @param cleanUp the clean up
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
958 * @throws UnsupportedEncodingException the unsupported encoding exception
959 * @throws AAIException the AAI exception
960 * @throws MalformedURLException the malformed URL exception
961 * @throws AAIUnknownObjectException
962 * @throws URISyntaxException
964 private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp, Edge edge) throws UnsupportedEncodingException, AAIUnknownObjectException {
967 //we must look up all parents in this case because we need to compute name-properties
968 //we cannot used the cached aaiUri to perform this action currently
969 Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp));
970 //damaged vertex found, ignore
971 if (!tuple.isPresent()) {
974 List<Introspector> list = tuple.get().getValue1();
975 URI uri = this.getURIFromList(list);
977 URIToRelationshipObject uriParser = null;
978 Introspector result = null;
980 uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
981 result = uriParser.getResult();
982 } catch (AAIException | URISyntaxException e) {
983 LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.get().getValue0().id().toString() + ": "
984 + e.getMessage() + " " + LogFormatTools.getStackTop(e));
985 if ("true".equals(cleanUp)) {
986 this.deleteWithTraversal(tuple.get().getValue0());
990 if (!list.isEmpty()) {
991 this.addRelatedToProperty(result, list.get(0));
994 if (edge != null && result.hasProperty("relationship-label")) {
995 result.setValue("relationship-label", edge.label());
998 return result.getUnderlyingObject();
1002 * Gets the URI for vertex.
1005 * @return the URI for vertex
1006 * @throws InstantiationException the instantiation exception
1007 * @throws IllegalAccessException the illegal access exception
1008 * @throws IllegalArgumentException the illegal argument exception
1009 * @throws InvocationTargetException the invocation target exception
1010 * @throws NoSuchMethodException the no such method exception
1011 * @throws SecurityException the security exception
1012 * @throws UnsupportedEncodingException the unsupported encoding exception
1013 * @throws AAIUnknownObjectException
1015 public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
1017 return getURIForVertex(v, false);
1020 public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
1021 URI uri = UriBuilder.fromPath("/unknown-uri").build();
1023 String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
1025 if (aaiUri != null && !overwrite) {
1026 uri = UriBuilder.fromPath(aaiUri).build();
1028 StopWatch.conditionalStart();
1029 Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(this.loader, v, false);
1030 dbTimeMsecs += StopWatch.stopIfStarted();
1031 if (tuple.isPresent()) {
1032 List<Introspector> list = tuple.get().getValue1();
1033 uri = this.getURIFromList(list);
1041 * Gets the URI from list.
1043 * @param list the list
1044 * @return the URI from list
1045 * @throws UnsupportedEncodingException the unsupported encoding exception
1047 private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
1049 StringBuilder sb = new StringBuilder();
1050 for (Introspector i : list) {
1051 sb.insert(0, i.getURI());
1054 uri = sb.toString();
1055 return UriBuilder.fromPath(uri).build();
1061 * @param start the start
1062 * @param removeDamaged the remove damaged
1063 * @return the parents
1064 * @throws InstantiationException the instantiation exception
1065 * @throws IllegalAccessException the illegal access exception
1066 * @throws IllegalArgumentException the illegal argument exception
1067 * @throws InvocationTargetException the invocation target exception
1068 * @throws NoSuchMethodException the no such method exception
1069 * @throws SecurityException the security exception
1070 * @throws AAIUnknownObjectException
1072 private Optional<Pair<Vertex, List<Introspector>>> getParents(Loader loader, Vertex start, boolean removeDamaged) {
1074 List<Vertex> results = this.engine.getQueryEngine().findParents(start);
1075 List<Introspector> objs = new ArrayList<>();
1076 boolean shortCircuit = false;
1077 for (Vertex v : results) {
1078 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1079 Introspector obj = null;
1080 //vertex on the other end of this edge is bad
1081 if (nodeType == null) {
1082 //log something here about what was found and that it was removed
1083 ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString());
1084 if (removeDamaged) {
1085 this.deleteWithTraversal(v);
1087 shortCircuit = true;
1090 obj = loader.introspectorFromName(nodeType);
1091 } catch (AAIUnknownObjectException e) {
1092 LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion());
1098 //can't make a valid path because we don't understand this object
1101 this.simpleDbToObject(obj, v);
1106 //stop processing and don't return anything for this bad vertex
1108 return Optional.empty();
1111 return Optional.of(new Pair<>(results.get(results.size()-1), objs));
1114 * Takes a list of vertices and a list of objs and assumes they are in
1115 * the order you want the URIs to be nested.
1116 * [A,B,C] creates uris [A, AB, ABC]
1119 * @throws UnsupportedEncodingException
1120 * @throws URISyntaxException
1122 public void setCachedURIs(List<Vertex> vertices, List<Introspector> objs) throws UnsupportedEncodingException, URISyntaxException {
1124 StringBuilder uriChain = new StringBuilder();
1125 for (int i = 0; i < vertices.size(); i++) {
1128 v = vertices.get(i);
1129 aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
1130 if (aaiUri != null) {
1131 uriChain.append(aaiUri);
1133 URI uri = UriBuilder.fromPath(objs.get(i).getURI()).build();
1134 aaiUri = uri.toString();
1135 uriChain.append(aaiUri);
1136 v.property(AAIProperties.AAI_URI, uriChain.toString());
1147 * @throws AAIUnknownObjectException
1148 * @throws IllegalArgumentException elated to property.
1150 * @param relationship the relationship
1151 * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
1153 public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
1154 String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
1155 List<Introspector> relatedToProperties = new ArrayList<>();
1157 if (nameProps != null) {
1158 String[] props = nameProps.split(",");
1159 for (String prop : props) {
1160 Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
1161 relatedTo.setValue("property-key", child.getDbName() + "." + prop);
1162 relatedTo.setValue("property-value", child.getValue(prop));
1163 relatedToProperties.add(relatedTo);
1167 if (!relatedToProperties.isEmpty()) {
1168 List relatedToList = (List)relationship.getValue("related-to-property");
1169 for (Introspector obj : relatedToProperties) {
1170 relatedToList.add(obj.getUnderlyingObject());
1179 * @param relationship the relationship
1180 * @param inputVertex the input vertex
1181 * @return true, if successful
1182 * @throws UnsupportedEncodingException the unsupported encoding exception
1183 * @throws AAIException the AAI exception
1185 public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1187 Vertex relatedVertex = null;
1188 StopWatch.conditionalStart();
1189 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1191 String label = null;
1192 if (relationship.hasProperty("relationship-label")) {
1193 label = relationship.getValue("relationship-label");
1196 List<Vertex> results = parser.getQueryBuilder().toList();
1197 if (results.isEmpty()) {
1198 dbTimeMsecs += StopWatch.stopIfStarted();
1199 AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
1200 e.getTemplateVars().add(parser.getResultType());
1201 e.getTemplateVars().add(parser.getUri().toString());
1204 //still an issue if there's more than one
1205 relatedVertex = results.get(0);
1208 if (relatedVertex != null) {
1212 e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1214 edgeRules.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
1216 //attempted to link two vertexes already linked
1219 dbTimeMsecs += StopWatch.stopIfStarted();
1223 dbTimeMsecs += StopWatch.stopIfStarted();
1228 * Gets all the edges between of the type.
1230 * @param aVertex the out vertex
1231 * @param bVertex the in vertex
1232 * @return the edges between
1233 * @throws AAIException the AAI exception
1234 * @throws NoEdgeRuleFoundException
1236 private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
1238 List<Edge> result = new ArrayList<>();
1240 if (bVertex != null) {
1241 GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1242 findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
1243 if (EdgeType.TREE.equals(type)) {
1244 findEdgesBetween = findEdgesBetween.not(__.has(EdgeProperty.CONTAINS.toString(), "NONE"));
1246 findEdgesBetween = findEdgesBetween.has(EdgeProperty.CONTAINS.toString(), "NONE");
1248 findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
1249 result = findEdgesBetween.toList();
1255 * Gets all the edges between the vertexes with the label and type.
1257 * @param aVertex the out vertex
1258 * @param bVertex the in vertex
1260 * @return the edges between
1261 * @throws AAIException the AAI exception
1263 private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1265 List<Edge> result = new ArrayList<>();
1267 if (bVertex != null) {
1268 EdgeRule rule = edgeRules.getEdgeRule(type, aVertex, bVertex, label);
1269 List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
1270 for (Edge edge : edges) {
1271 if (edge.label().equals(rule.getLabel())) {
1281 * Gets the edge between with the label and edge type.
1283 * @param aVertex the out vertex
1284 * @param bVertex the in vertex
1286 * @return the edge between
1287 * @throws AAIException the AAI exception
1288 * @throws NoEdgeRuleFoundException
1290 public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1292 StopWatch.conditionalStart();
1293 if (bVertex != null) {
1295 List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex, label);
1297 if (!edges.isEmpty()) {
1298 dbTimeMsecs += StopWatch.stopIfStarted();
1299 return edges.get(0);
1303 dbTimeMsecs += StopWatch.stopIfStarted();
1306 public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
1307 return this.getEdgeBetween(type, aVertex, bVertex, null);
1314 * @param relationship the relationship
1315 * @param inputVertex the input vertex
1316 * @return true, if successful
1317 * @throws UnsupportedEncodingException the unsupported encoding exception
1318 * @throws AAIException the AAI exception
1320 public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
1322 Vertex relatedVertex = null;
1323 StopWatch.conditionalStart();
1324 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1326 List<Vertex> results = parser.getQueryBuilder().toList();
1328 String label = null;
1329 if (relationship.hasProperty("relationship-label")) {
1330 label = relationship.getValue("relationship-label");
1333 if (results.isEmpty()) {
1334 dbTimeMsecs += StopWatch.stopIfStarted();
1338 relatedVertex = results.get(0);
1341 edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1342 } catch (NoEdgeRuleFoundException e) {
1343 dbTimeMsecs += StopWatch.stopIfStarted();
1344 throw new AAIException("AAI_6129", e);
1348 dbTimeMsecs += StopWatch.stopIfStarted();
1351 dbTimeMsecs += StopWatch.stopIfStarted();
1358 * Delete items with traversal.
1360 * @param vertexes the vertexes
1361 * @throws IllegalStateException the illegal state exception
1363 public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
1365 for (Vertex v : vertexes) {
1366 LOGGER.debug("About to delete the vertex with id: " + v.id());
1367 deleteWithTraversal(v);
1373 * Delete with traversal.
1375 * @param startVertex the start vertex
1377 public void deleteWithTraversal(Vertex startVertex) {
1378 StopWatch.conditionalStart();
1379 List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
1381 for (Vertex v : results) {
1382 LOGGER.warn("Removing vertex " + v.id().toString());
1386 dbTimeMsecs += StopWatch.stopIfStarted();
1393 * @param resourceVersion the resource version
1394 * @throws IllegalArgumentException the illegal argument exception
1395 * @throws AAIException the AAI exception
1396 * @throws InterruptedException the interrupted exception
1398 public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
1400 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1403 deleteWithTraversal(v);
1404 } catch (IllegalStateException e) {
1405 throw new AAIException("AAI_6110", e);
1414 * Verify delete semantics.
1416 * @param vertex the vertex
1417 * @param resourceVersion the resource version
1418 * @return true, if successful
1419 * @throws AAIException the AAI exception
1421 private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
1422 boolean result = true;
1423 String nodeType = "";
1424 String errorDetail = " unknown delete semantic found";
1425 String aaiExceptionCode = "";
1426 nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1427 if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
1429 StopWatch.conditionalStart();
1430 List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertex).union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE), __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE)).dedup().toList();
1432 dbTimeMsecs += StopWatch.stopIfStarted();
1433 if (!preventDeleteVertices.isEmpty()) {
1434 aaiExceptionCode = "AAI_6110";
1435 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);
1439 throw new AAIException(aaiExceptionCode, errorDetail);
1445 * Verify resource version.
1447 * @param action the action
1448 * @param nodeType the node type
1449 * @param currentResourceVersion the current resource version
1450 * @param resourceVersion the resource version
1451 * @param uri the uri
1452 * @return true, if successful
1453 * @throws AAIException the AAI exception
1455 public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
1456 String enabled = "";
1457 String errorDetail = "";
1458 String aaiExceptionCode = "";
1459 if (currentResourceVersion == null) {
1460 currentResourceVersion = "";
1463 if (resourceVersion == null) {
1464 resourceVersion = "";
1467 enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
1468 } catch (AAIException e) {
1469 ErrorLogHelper.logException(e);
1471 // We're only doing the resource version checks for v5 and later
1472 if (enabled.equals("true")) {
1473 if (!currentResourceVersion.equals(resourceVersion)) {
1474 if (action.equals("create") && !resourceVersion.equals("")) {
1475 errorDetail = "resource-version passed for " + action + " of " + uri;
1476 aaiExceptionCode = "AAI_6135";
1477 } else if (resourceVersion.equals("")) {
1478 errorDetail = "resource-version not passed for " + action + " of " + uri;
1479 aaiExceptionCode = "AAI_6130";
1481 errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
1482 aaiExceptionCode = "AAI_6131";
1485 throw new AAIException(aaiExceptionCode, errorDetail);
1493 * Convert from camel case.
1495 * @param name the name
1496 * @return the string
1498 private String convertFromCamelCase (String name) {
1500 result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
1502 NamingExceptions exceptions = NamingExceptions.getInstance();
1503 result = exceptions.getDBName(result);
1508 private boolean canModify(Introspector obj, String propName, String requestContext) {
1509 final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
1510 if (readOnly != null) {
1511 final String[] items = readOnly.split(",");
1512 for (String item : items) {
1513 if (requestContext.equals(item)) {
1521 private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
1523 SideEffectRunner runner = new SideEffectRunner
1524 .Builder(this.engine, this).addSideEffect(DataCopy.class).build();
1526 runner.execute(obj, self);
1529 private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
1531 SideEffectRunner runner = new SideEffectRunner
1532 .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
1534 runner.execute(obj, self);
1537 private void enrichData(Introspector obj, Vertex self) throws AAIException {
1539 SideEffectRunner runner = new SideEffectRunner
1540 .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
1542 runner.execute(obj, self);
1545 public double getDBTimeMsecs() {
1546 return (dbTimeMsecs);
1550 * Db to object With Filters
1551 * This is for a one-time run with Tenant Isloation to only filter relationships
1552 * TODO: Chnage the original dbToObject to take filter parent/cousins
1554 * @param vertices the vertices
1555 * @param obj the obj
1556 * @param depth the depth
1557 * @param cleanUp the clean up
1558 * @return the introspector
1559 * @throws AAIException the AAI exception
1560 * @throws IllegalAccessException the illegal access exception
1561 * @throws IllegalArgumentException the illegal argument exception
1562 * @throws InvocationTargetException the invocation target exception
1563 * @throws SecurityException the security exception
1564 * @throws InstantiationException the instantiation exception
1565 * @throws NoSuchMethodException the no such method exception
1566 * @throws UnsupportedEncodingException the unsupported encoding exception
1567 * @throws MalformedURLException the malformed URL exception
1568 * @throws AAIUnknownObjectException
1569 * @throws URISyntaxException
1571 //TODO - See if you can merge the 2 dbToObjectWithFilters
1572 public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, List<String> filterCousinNodes, List<String> filterParentNodes) throws AAIException, UnsupportedEncodingException {
1573 String cleanUp = "false";
1579 boolean modified = false;
1580 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
1581 List<Object> getList = null;
1582 Vertex[] vertices = null;
1584 if (!(obj.isComplexType(property) || obj.isListType(property))) {
1585 this.copySimpleProperty(property, obj, v);
1588 if (obj.isComplexType(property)) {
1589 /* container case */
1591 if (!property.equals("relationship-list") && depth >= 0) {
1592 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
1593 Object result = dbToObjectWithFilters(argumentObject, v, seen, depth+1, nodeOnly, filterCousinNodes, filterParentNodes);
1594 if (result != null) {
1595 obj.setValue(property, argumentObject.getUnderlyingObject());
1598 } else if (property.equals("relationship-list") && !nodeOnly){
1599 /* relationships need to be handled correctly */
1600 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
1601 relationshipList = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
1602 if (relationshipList != null) {
1604 obj.setValue(property, relationshipList.getUnderlyingObject());
1609 } else if (obj.isListType(property)) {
1611 if (property.equals("any")) {
1614 String genericType = obj.getGenericTypeClass(property).getSimpleName();
1615 if (obj.isComplexGenericType(property) && depth >= 0) {
1616 final String childDbName = convertFromCamelCase(genericType);
1617 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1620 boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains);
1624 rule = edgeRules.getEdgeRule(EdgeType.TREE, vType, childDbName);
1625 if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
1626 //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
1627 Direction ruleDirection = rule.getDirection();
1628 Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
1629 List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
1630 itr = verticesList.stream().filter(item -> {
1631 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
1633 if (itr.hasNext()) {
1634 getList = (List<Object>)obj.getValue(property);
1638 while (itr.hasNext()) {
1639 Vertex childVertex = itr.next();
1640 if (!seen.contains(childVertex)) {
1641 Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
1643 Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes);
1644 if (result != null) {
1645 getList.add(argumentObject.getUnderlyingObject());
1651 LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
1654 if (processed == 0) {
1655 //vertices were all seen, reset the list
1658 if (processed > 0) {
1662 } else if (obj.isSimpleGenericType(property)) {
1663 List<Object> temp = this.engine.getListProperty(v, property);
1665 getList = (List<Object>)obj.getValue(property);
1666 getList.addAll(temp);
1677 //no changes were made to this obj, discard the instance
1681 this.enrichData(obj, v);
1687 * Creates the relationship list with the filtered node types.
1690 * @param obj the obj
1691 * @param cleanUp the clean up
1692 * @return the object
1693 * @throws InstantiationException the instantiation exception
1694 * @throws IllegalAccessException the illegal access exception
1695 * @throws IllegalArgumentException the illegal argument exception
1696 * @throws InvocationTargetException the invocation target exception
1697 * @throws NoSuchMethodException the no such method exception
1698 * @throws SecurityException the security exception
1699 * @throws UnsupportedEncodingException the unsupported encoding exception
1700 * @throws AAIException the AAI exception
1701 * @throws MalformedURLException the malformed URL exception
1702 * @throws URISyntaxException
1704 private Introspector createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
1705 List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
1707 Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
1708 String node = (String)item.property(AAIProperties.NODE_TYPE).orElse("");
1709 return filterNodes.parallelStream().anyMatch(node::contains);
1713 List<Vertex> cousins = (List<Vertex>)IteratorUtils.toList(cousinVertices);
1715 //items.parallelStream().anyMatch(inputStr::contains)
1716 List<Object> relationshipObjList = obj.getValue("relationship");
1717 for (Vertex cousin : cousins) {
1719 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1720 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
1721 if (result != null) {
1722 relationshipObjList.add(result);
1728 if (relationshipObjList.isEmpty()) {