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=========================================================
21 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;
27 import java.io.UnsupportedEncodingException;
28 import java.lang.reflect.Array;
29 import java.lang.reflect.InvocationTargetException;
30 import java.net.MalformedURLException;
32 import java.net.URISyntaxException;
34 import java.util.concurrent.ExecutionException;
35 import java.util.concurrent.ExecutorService;
36 import java.util.concurrent.Future;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
40 import javax.ws.rs.core.UriBuilder;
42 import org.apache.commons.collections.IteratorUtils;
43 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
44 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
45 import org.apache.tinkerpop.gremlin.structure.Direction;
46 import org.apache.tinkerpop.gremlin.structure.Edge;
47 import org.apache.tinkerpop.gremlin.structure.Vertex;
48 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
49 import org.janusgraph.core.SchemaViolationException;
50 import org.javatuples.Triplet;
51 import org.onap.aai.concurrent.AaiCallable;
52 import org.onap.aai.config.SpringContextAware;
53 import org.onap.aai.db.props.AAIProperties;
54 import org.onap.aai.edges.EdgeIngestor;
55 import org.onap.aai.edges.EdgeRule;
56 import org.onap.aai.edges.EdgeRuleQuery;
57 import org.onap.aai.edges.TypeAlphabetizer;
58 import org.onap.aai.edges.enums.AAIDirection;
59 import org.onap.aai.edges.enums.EdgeField;
60 import org.onap.aai.edges.enums.EdgeProperty;
61 import org.onap.aai.edges.enums.EdgeType;
62 import org.onap.aai.edges.exceptions.AmbiguousRuleChoiceException;
63 import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException;
64 import org.onap.aai.exceptions.AAIException;
65 import org.onap.aai.introspection.*;
66 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
67 import org.onap.aai.introspection.sideeffect.*;
68 import org.onap.aai.logging.ErrorLogHelper;
69 import org.onap.aai.logging.LogFormatTools;
70 import org.onap.aai.logging.LoggingContext;
71 import org.onap.aai.logging.StopWatch;
72 import org.onap.aai.parsers.query.QueryParser;
73 import org.onap.aai.parsers.uri.URIParser;
74 import org.onap.aai.parsers.uri.URIToRelationshipObject;
75 import org.onap.aai.query.builder.QueryBuilder;
76 import org.onap.aai.schema.enums.ObjectMetadata;
77 import org.onap.aai.schema.enums.PropertyMetadata;
78 import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
79 import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
80 import org.onap.aai.serialization.engines.TransactionalGraphEngine;
81 import org.onap.aai.serialization.engines.query.QueryEngine;
82 import org.onap.aai.setup.SchemaVersion;
83 import org.onap.aai.setup.SchemaVersions;
84 import org.onap.aai.util.AAIConfig;
85 import org.onap.aai.util.AAIConstants;
86 import org.onap.aai.workarounds.NamingExceptions;
87 import org.springframework.context.ApplicationContext;
89 public class DBSerializer {
91 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
93 private static final String IMPLICIT_DELETE = "Implicit DELETE";
95 private static final String MISSING_REQUIRED_NODE_PROPERTY = "Vertex missing required aai-node-type property";
97 private final TransactionalGraphEngine engine;
98 private final String sourceOfTruth;
99 private final ModelType introspectionType;
100 private final SchemaVersion version;
101 private final Loader latestLoader;
102 private EdgeSerializer edgeSer;
103 private EdgeIngestor edgeRules;
104 private final Loader loader;
105 private final String baseURL;
106 private double dbTimeMsecs = 0;
107 private long currentTimeMillis;
109 private SchemaVersions schemaVersions;
110 private Set<String> namedPropNodes;
113 * Instantiates a new DB serializer.
115 * @param version the version
116 * @param engine the engine
117 * @param introspectionType the introspection type
118 * @param sourceOfTruth the source of truth
119 * @throws AAIException
121 public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType,
122 String sourceOfTruth) throws AAIException {
123 this.engine = engine;
124 this.sourceOfTruth = sourceOfTruth;
125 this.introspectionType = introspectionType;
126 this.schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions");
127 SchemaVersion LATEST = schemaVersions.getDefaultVersion();
129 SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST);
130 this.version = version;
132 SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version);
133 this.namedPropNodes = this.latestLoader.getNamedPropNodes();
134 this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
135 this.currentTimeMillis = System.currentTimeMillis();
139 private void initBeans() {
140 // TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
141 ApplicationContext ctx = SpringContextAware.getApplicationContext();
142 EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
144 EdgeSerializer es = ctx.getBean(EdgeSerializer.class);
145 setEdgeSerializer(es);
148 private void backupESInit() {
149 setEdgeSerializer(new EdgeSerializer(this.edgeRules));
152 public void setEdgeSerializer(EdgeSerializer edgeSer) {
153 this.edgeSer = edgeSer;
156 public EdgeSerializer getEdgeSeriailizer() {
160 public void setEdgeIngestor(EdgeIngestor ei) {
164 public EdgeIngestor getEdgeIngestor() {
165 return this.edgeRules;
169 * Touch standard vertex properties.
172 * @param isNewVertex the is new vertex
174 public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
175 String timeNowInSec = Long.toString(currentTimeMillis);
178 v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
179 v.property(AAIProperties.CREATED_TS, timeNowInSec);
180 v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
182 v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec);
183 v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
184 v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
188 private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) {
190 v.property(AAIProperties.NODE_TYPE, nodeType);
191 touchStandardVertexProperties(v, isNewVertex);
196 * Creates the new vertex.
198 * @param wrappedObject the wrapped object
200 * @throws UnsupportedEncodingException the unsupported encoding exception
201 * @throws AAIException the AAI exception
203 public Vertex createNewVertex(Introspector wrappedObject) {
206 StopWatch.conditionalStart();
207 v = this.engine.tx().addVertex();
208 touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
210 dbTimeMsecs += StopWatch.stopIfStarted();
218 * @param className the class name
222 * Removes the classpath from a class name
224 public String trimClassName(String className) {
225 String returnValue = "";
227 if (className.lastIndexOf('.') == -1) {
230 returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
240 * @param uriQuery the uri query
241 * @param identifier the identifier
242 * @throws SecurityException the security exception
243 * @throws IllegalAccessException the illegal access exception
244 * @throws IllegalArgumentException the illegal argument exception
245 * @throws InvocationTargetException the invocation target exception
246 * @throws InstantiationException the instantiation exception
247 * @throws InterruptedException the interrupted exception
248 * @throws NoSuchMethodException the no such method exception
249 * @throws AAIException the AAI exception
250 * @throws UnsupportedEncodingException the unsupported encoding exception
251 * @throws AAIUnknownObjectException
253 public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier,
254 String requestContext) throws AAIException, UnsupportedEncodingException {
255 StopWatch.conditionalStart();
257 if (uriQuery.isDependent()) {
258 // try to find the parent
259 List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
260 if (!vertices.isEmpty()) {
261 Vertex parent = vertices.get(0);
262 this.reflectDependentVertex(parent, v, obj, requestContext);
264 dbTimeMsecs += StopWatch.stopIfStarted();
265 throw new AAIException("AAI_6114",
266 "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
269 serializeSingleVertex(v, obj, requestContext);
272 } catch (SchemaViolationException e) {
273 dbTimeMsecs += StopWatch.stopIfStarted();
274 throw new AAIException("AAI_6117", e);
276 dbTimeMsecs += StopWatch.stopIfStarted();
279 public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext)
280 throws UnsupportedEncodingException, AAIException {
281 StopWatch.conditionalStart();
283 boolean isTopLevel = obj.isTopLevel();
285 addUriIfNeeded(v, obj.getURI());
288 processObject(obj, v, requestContext);
290 URI uri = this.getURIForVertex(v);
291 URIParser parser = new URIParser(this.loader, uri);
292 if (parser.validate()) {
293 addUriIfNeeded(v, uri.toString());
296 } catch (SchemaViolationException e) {
297 throw new AAIException("AAI_6117", e);
299 dbTimeMsecs += StopWatch.stopIfStarted();
303 private void addUriIfNeeded(Vertex v, String uri) {
304 VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
305 if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) {
306 v.property(AAIProperties.AAI_URI, uri);
313 * @param <T> the generic type
317 * @throws IllegalAccessException the illegal access exception
318 * @throws IllegalArgumentException the illegal argument exception
319 * @throws InvocationTargetException the invocation target exception
320 * @throws InstantiationException the instantiation exception
321 * @throws NoSuchMethodException the no such method exception
322 * @throws SecurityException the security exception
323 * @throws AAIException the AAI exception
324 * @throws UnsupportedEncodingException the unsupported encoding exception
325 * @throws AAIUnknownObjectException
328 * Helper method for reflectToDb
329 * Handles all the property setting
331 private <T> List<Vertex> processObject(Introspector obj, Vertex v, String requestContext)
332 throws UnsupportedEncodingException, AAIException {
333 Set<String> properties = new LinkedHashSet<>(obj.getProperties());
334 properties.remove(AAIProperties.RESOURCE_VERSION);
335 List<Vertex> dependentVertexes = new ArrayList<>();
336 List<Vertex> processedVertexes = new ArrayList<>();
337 boolean isComplexType = false;
338 boolean isListType = false;
339 if (!obj.isContainer()) {
340 this.touchStandardVertexProperties(v, false);
342 this.executePreSideEffects(obj, v);
343 for (String property : properties) {
345 final String propertyType;
346 propertyType = obj.getType(property);
347 isComplexType = obj.isComplexType(property);
348 isListType = obj.isListType(property);
349 value = obj.getValue(property);
351 if (!(isComplexType || isListType)) {
352 boolean canModify = this.canModify(obj, property, requestContext);
355 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
356 String dbProperty = property;
357 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
358 dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
360 if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
361 // data linked properties are ephemeral
362 // they are populated dynamically on GETs
366 if (!value.equals(v.property(dbProperty).orElse(null))) {
367 if (propertyType.toLowerCase().contains(".long")) {
368 v.property(dbProperty, new Integer(((Long) value).toString()));
370 v.property(dbProperty, value);
374 v.property(dbProperty).remove();
377 } else if (isListType) {
378 List<Object> list = (List<Object>) value;
379 if (obj.isComplexGenericType(property)) {
381 for (Object o : list) {
382 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
383 child.setURIChain(obj.getURI());
384 processedVertexes.add(reflectDependentVertex(v, child, requestContext));
389 engine.setListProperty(v, property, list);
392 // method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge
393 // back to this method
394 if (value != null) { // effectively ignore complex properties not included in the object we're
396 if (value.getClass().isArray()) {
398 int length = Array.getLength(value);
399 for (int i = 0; i < length; i++) {
400 Object arrayElement = Array.get(value, i);
401 Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
402 child.setURIChain(obj.getURI());
403 processedVertexes.add(reflectDependentVertex(v, child, requestContext));
406 } else if (!property.equals("relationship-list")) {
408 Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
409 if (introspector.isContainer()) {
410 dependentVertexes.addAll(
411 this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
412 introspector.setURIChain(obj.getURI());
414 processedVertexes.addAll(processObject(introspector, v, requestContext));
417 dependentVertexes.addAll(
418 this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
419 processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
422 } else if (property.equals("relationship-list")) {
423 handleRelationships(obj, v);
428 this.writeThroughDefaults(v, obj);
429 /* handle those vertexes not touched */
430 for (Vertex toBeRemoved : processedVertexes) {
431 dependentVertexes.remove(toBeRemoved);
434 // If the dependent vertices are not empty, then with
435 // the current behaviour, it should remove the vertices implicitly
436 // We are updating the code to properly log which call
437 // is doing this so the SE can work with the clients making the call to
438 // tell them not to call this API and can hopefully deprecate this
439 // functionality in the future releases
440 if (!dependentVertexes.isEmpty()) {
442 LoggingContext.responseDescription(IMPLICIT_DELETE);
444 // Find all the deletable vertices from the dependent vertices that should be deleted
445 // So for each of the following dependent vertices,
446 // we will use the edge properties and do the cascade delete
447 List<Vertex> impliedDeleteVertices = this.engine.getQueryEngine().findDeletable(dependentVertexes);
448 int impliedDeleteCount = impliedDeleteVertices.size();
451 "For the vertex with id {}, doing an implicit delete on update will delete total of {} vertexes",
452 v.id(), impliedDeleteCount);
454 String impliedDeleteLogEnabled = AAIConfig.get(AAIConstants.AAI_IMPLIED_DELETE_LOG_ENABLED, "true");
456 int impliedDeleteLogLimit = AAIConfig.getInt(AAIConstants.AAI_IMPLIED_DELETE_LOG_LIMIT, "-1");
458 if (impliedDeleteLogLimit == -1) {
459 impliedDeleteLogLimit = Integer.MAX_VALUE;
462 // If the logging is enabled for implied delete
463 // then log the payload in the latest format
464 if ("true".equals(impliedDeleteLogEnabled) && impliedDeleteCount <= impliedDeleteLogLimit) {
465 for (Vertex vertex : impliedDeleteVertices) {
466 Introspector introspector = null;
468 introspector = getLatestVersionView(vertex);
469 if (LOGGER.isInfoEnabled()) {
470 LOGGER.info("Implied delete object in json format {}", introspector.marshal(false));
472 } catch (Exception ex) {
474 "Encountered an exception during retrieval of vertex properties with vertex-id {} -> {}",
475 v.id(), LogFormatTools.getStackTop(ex));
480 // After all the appropriate logging, calling the delete to delete the affected vertices
481 this.delete(impliedDeleteVertices);
484 this.executePostSideEffects(obj, v);
485 return processedVertexes;
489 * Handle relationships.
492 * @param vertex the vertex
493 * @throws SecurityException the security exception
494 * @throws IllegalAccessException the illegal access exception
495 * @throws IllegalArgumentException the illegal argument exception
496 * @throws InvocationTargetException the invocation target exception
497 * @throws UnsupportedEncodingException the unsupported encoding exception
498 * @throws AAIException the AAI exception
501 * Handles the explicit relationships defined for an obj
503 private void handleRelationships(Introspector obj, Vertex vertex)
504 throws UnsupportedEncodingException, AAIException {
506 Introspector wrappedRl = obj.getWrappedValue("relationship-list");
507 processRelationshipList(wrappedRl, vertex);
512 * Process relationship list.
514 * @param wrapped the wrapped
516 * @throws UnsupportedEncodingException the unsupported encoding exception
517 * @throws AAIException the AAI exception
519 private void processRelationshipList(Introspector wrapped, Vertex v)
520 throws UnsupportedEncodingException, AAIException {
522 List<Object> relationships = (List<Object>) wrapped.getValue("relationship");
524 List<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
525 List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
527 for (Object relationship : relationships) {
529 Vertex cousinVertex = null;
531 Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
532 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
534 if (wrappedRel.hasProperty("relationship-label")) {
535 label = wrappedRel.getValue("relationship-label");
538 List<Vertex> results = parser.getQueryBuilder().toList();
539 if (results.isEmpty()) {
540 final AAIException ex = new AAIException("AAI_6129",
541 "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
542 ex.getTemplateVars().add(parser.getResultType());
543 ex.getTemplateVars().add(parser.getUri().toString());
546 // still an issue if there's more than one
547 cousinVertex = results.get(0);
550 if (cousinVertex != null) {
551 String vType = (String) v.property(AAIProperties.NODE_TYPE).value();
552 String cousinType = (String) cousinVertex.property(AAIProperties.NODE_TYPE).value();
553 EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label);
555 if (!edgeRules.hasRule(baseQ.build())) {
556 throw new AAIException("AAI_6120",
557 "No EdgeRule found for passed nodeTypes: "
558 + v.property(AAIProperties.NODE_TYPE).value().toString() + ", "
559 + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString()
560 + (label != null ? (" with label " + label) : "") + ".");
561 } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build())
562 && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
563 throw new AAIException("AAI_6145");
566 e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
569 addEdges.add(new Triplet<>(v, cousinVertex, label));
571 existingEdges.remove(e);
576 for (Edge edge : existingEdges) {
579 for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
581 edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(),
582 triplet.getValue2());
583 } catch (NoEdgeRuleFoundException e) {
584 throw new AAIException("AAI_6129", e);
591 * Write through defaults.
595 * @throws AAIUnknownObjectException
597 private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
598 Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
599 if (latest != null) {
600 Set<String> required = latest.getRequiredProperties();
602 for (String field : required) {
603 String defaultValue = null;
604 Object vertexProp = null;
605 defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
606 if (defaultValue != null) {
607 vertexProp = v.<Object>property(field).orElse(null);
608 if (vertexProp == null) {
609 v.property(field, defaultValue);
618 * Reflect dependent vertex.
621 * @param dependentObj the dependent obj
623 * @throws IllegalAccessException the illegal access exception
624 * @throws IllegalArgumentException the illegal argument exception
625 * @throws InvocationTargetException the invocation target exception
626 * @throws InstantiationException the instantiation exception
627 * @throws NoSuchMethodException the no such method exception
628 * @throws SecurityException the security exception
629 * @throws AAIException the AAI exception
630 * @throws UnsupportedEncodingException the unsupported encoding exception
631 * @throws AAIUnknownObjectException
633 private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext)
634 throws AAIException, UnsupportedEncodingException {
636 // QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
637 // List<Vertex> items = p.getQuery().toList();
638 QueryBuilder<Vertex> query = this.engine.getQueryBuilder(v);
639 query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
640 query.createKeyQuery(dependentObj);
642 List<Vertex> items = query.toList();
644 Vertex dependentVertex = null;
645 if (items.size() == 1) {
646 dependentVertex = items.get(0);
647 this.verifyResourceVersion("update", dependentObj.getDbName(),
648 dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null),
649 (String) dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String) dependentObj.getURI());
651 this.verifyResourceVersion("create", dependentObj.getDbName(), "",
652 (String) dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String) dependentObj.getURI());
653 dependentVertex = createNewVertex(dependentObj);
656 return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
661 * Reflect dependent vertex.
663 * @param parent the parent
664 * @param child the child
667 * @throws IllegalAccessException the illegal access exception
668 * @throws IllegalArgumentException the illegal argument exception
669 * @throws InvocationTargetException the invocation target exception
670 * @throws InstantiationException the instantiation exception
671 * @throws NoSuchMethodException the no such method exception
672 * @throws SecurityException the security exception
673 * @throws AAIException the AAI exception
674 * @throws UnsupportedEncodingException the unsupported encoding exception
675 * @throws AAIUnknownObjectException
677 private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext)
678 throws AAIException, UnsupportedEncodingException {
680 String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
681 if (parentUri != null) {
684 addUriIfNeeded(child, parentUri + uri);
686 processObject(obj, child, requestContext);
689 e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
692 String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
693 if (canBeLinked != null && canBeLinked.equals("true")) {
694 Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class)
695 .createLoaderForVersion(introspectionType, getVerForContext(requestContext));
696 boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent)
697 .createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
699 child.property(AAIProperties.LINKED, true);
702 edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
708 private SchemaVersion getVerForContext(String requestContext) {
709 Pattern pattern = Pattern.compile("v[0-9]+");
710 Matcher m = pattern.matcher(requestContext);
714 return new SchemaVersion(requestContext);
721 * @param vertices the vertices
723 * @param depth the depth
724 * @param cleanUp the clean up
725 * @return the introspector
726 * @throws AAIException the AAI exception
727 * @throws IllegalAccessException the illegal access exception
728 * @throws IllegalArgumentException the illegal argument exception
729 * @throws InvocationTargetException the invocation target exception
730 * @throws SecurityException the security exception
731 * @throws InstantiationException the instantiation exception
732 * @throws NoSuchMethodException the no such method exception
733 * @throws UnsupportedEncodingException the unsupported encoding exception
734 * @throws MalformedURLException the malformed URL exception
735 * @throws AAIUnknownObjectException
736 * @throws URISyntaxException
738 public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly,
739 String cleanUp) throws UnsupportedEncodingException, AAIException {
740 final int internalDepth;
741 if (depth == Integer.MAX_VALUE) {
742 internalDepth = depth--;
744 internalDepth = depth;
746 StopWatch.conditionalStart();
747 if (vertices.size() > 1 && !obj.isContainer()) {
748 dbTimeMsecs += StopWatch.stopIfStarted();
749 throw new AAIException("AAI_6136",
750 "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
751 } else if (obj.isContainer()) {
753 String listProperty = null;
754 for (String property : obj.getProperties()) {
755 if (obj.isListType(property) && obj.isComplexGenericType(property)) {
756 listProperty = property;
760 final String propertyName = listProperty;
761 getList = (List) obj.getValue(listProperty);
764 * This is an experimental multithreading experiment
767 ExecutorService pool = GetAllPool.getInstance().getPool();
769 List<Future<Object>> futures = new ArrayList<>();
771 QueryEngine tgEngine = this.engine.getQueryEngine();
772 for (Vertex v : vertices) {
774 AaiCallable<Object> task = new AaiCallable<Object>() {
776 public Object process() throws UnsupportedEncodingException, AAIException {
777 Set<Vertex> seen = new HashSet<>();
778 Introspector childObject;
780 childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
781 } catch (AAIUnknownObjectException e) {
785 dbToObject(childObject, v, seen, internalDepth, nodeOnly, cleanUp);
786 } catch (UnsupportedEncodingException e) {
788 } catch (AAIException e) {
791 return childObject.getUnderlyingObject();
792 // getList.add(childObject.getUnderlyingObject());
795 futures.add(pool.submit(task));
798 for (Future<Object> future : futures) {
800 getList.add(future.get());
801 } catch (ExecutionException e) {
802 dbTimeMsecs += StopWatch.stopIfStarted();
803 throw new AAIException("AAI_4000", e);
804 } catch (InterruptedException e) {
805 dbTimeMsecs += StopWatch.stopIfStarted();
806 throw new AAIException("AAI_4000", e);
809 } else if (vertices.size() == 1) {
810 Set<Vertex> seen = new HashSet<>();
811 dbToObject(obj, vertices.get(0), seen, depth, nodeOnly, cleanUp);
816 dbTimeMsecs += StopWatch.stopIfStarted();
825 * @param seen the seen
826 * @param depth the depth
827 * @param cleanUp the clean up
828 * @return the introspector
829 * @throws IllegalAccessException the illegal access exception
830 * @throws IllegalArgumentException the illegal argument exception
831 * @throws InvocationTargetException the invocation target exception
832 * @throws SecurityException the security exception
833 * @throws InstantiationException the instantiation exception
834 * @throws NoSuchMethodException the no such method exception
835 * @throws UnsupportedEncodingException the unsupported encoding exception
836 * @throws AAIException the AAI exception
837 * @throws MalformedURLException the malformed URL exception
838 * @throws AAIUnknownObjectException
839 * @throws URISyntaxException
841 private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly,
842 String cleanUp) throws AAIException, UnsupportedEncodingException {
850 boolean modified = false;
851 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
852 List<Object> getList = null;
853 Vertex[] vertices = null;
855 if (!(obj.isComplexType(property) || obj.isListType(property))) {
856 this.copySimpleProperty(property, obj, v);
859 if (obj.isComplexType(property)) {
862 if (!property.equals("relationship-list") && depth >= 0) {
863 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
864 Object result = dbToObject(argumentObject, v, seen, depth + 1, nodeOnly, cleanUp);
865 if (result != null) {
866 obj.setValue(property, argumentObject.getUnderlyingObject());
869 } else if (property.equals("relationship-list") && !nodeOnly) {
870 /* relationships need to be handled correctly */
871 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
872 relationshipList = createRelationshipList(v, relationshipList, cleanUp);
873 if (relationshipList != null) {
875 obj.setValue(property, relationshipList.getUnderlyingObject());
880 } else if (obj.isListType(property)) {
882 if (property.equals("any")) {
885 String genericType = obj.getGenericTypeClass(property).getSimpleName();
886 if (obj.isComplexGenericType(property) && depth >= 0) {
887 final String childDbName = convertFromCamelCase(genericType);
888 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
892 rule = edgeRules.getRule(
893 new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build());
894 } catch (EdgeRuleNotFoundException e) {
895 throw new NoEdgeRuleFoundException(e);
896 } catch (AmbiguousRuleChoiceException e) {
897 throw new MultipleEdgeRuleFoundException(e);
899 if (!rule.getContains().equals(AAIDirection.NONE.toString())) {
900 // vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(),
902 Direction ruleDirection = rule.getDirection();
903 Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
904 List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr);
905 itr = verticesList.stream().filter(item -> {
906 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
909 getList = (List<Object>) obj.getValue(property);
913 while (itr.hasNext()) {
914 Vertex childVertex = itr.next();
915 if (!seen.contains(childVertex)) {
916 Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
919 dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
920 if (result != null) {
921 getList.add(argumentObject.getUnderlyingObject());
927 LOGGER.warn("Cycle found while serializing vertex id={}",
928 childVertex.id().toString());
931 if (processed == 0) {
932 // vertices were all seen, reset the list
939 } else if (obj.isSimpleGenericType(property)) {
940 List<Object> temp = this.engine.getListProperty(v, property);
942 getList = (List<Object>) obj.getValue(property);
943 getList.addAll(temp);
954 // no changes were made to this obj, discard the instance
958 this.enrichData(obj, v);
963 public Introspector getVertexProperties(Vertex v) throws AAIException, UnsupportedEncodingException {
964 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
965 if (nodeType == null) {
966 throw new AAIException("AAI_6143");
969 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
970 Set<Vertex> seen = new HashSet<>();
972 String cleanUp = "false";
973 boolean nodeOnly = true;
974 StopWatch.conditionalStart();
975 this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
976 dbTimeMsecs += StopWatch.stopIfStarted();
981 public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException {
982 String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
983 if (nodeType == null) {
984 throw new AAIException("AAI_6143");
986 Introspector obj = this.latestLoader.introspectorFromName(nodeType);
987 Set<Vertex> seen = new HashSet<>();
988 int depth = AAIProperties.MAXIMUM_DEPTH;
989 String cleanUp = "false";
990 boolean nodeOnly = false;
991 StopWatch.conditionalStart();
992 this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
993 dbTimeMsecs += StopWatch.stopIfStarted();
998 * Copy simple property.
1000 * @param property the property
1001 * @param obj the obj
1003 * @throws InstantiationException the instantiation exception
1004 * @throws IllegalAccessException the illegal access exception
1005 * @throws IllegalArgumentException the illegal argument exception
1006 * @throws InvocationTargetException the invocation target exception
1007 * @throws NoSuchMethodException the no such method exception
1008 * @throws SecurityException the security exception
1010 private void copySimpleProperty(String property, Introspector obj, Vertex v) {
1011 final Object temp = getProperty(obj, property, v);
1013 obj.setValue(property, temp);
1018 * Load the introspector from the hashmap for the given property key
1020 * @param property - vertex property
1021 * @param obj - introspector object representing the vertex
1022 * @param hashMap - Containing a list of pre-fetched properties for a given vertex
1024 private void copySimplePropertyFromHashMap(String property, Introspector obj, Map<String, Object> hashMap) {
1026 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
1027 String dbPropertyName = property;
1029 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
1030 dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
1033 final Object temp = hashMap.getOrDefault(dbPropertyName, null);
1036 obj.setValue(property, temp);
1041 * Simple db to object.
1043 * @param obj the obj
1045 * @throws InstantiationException the instantiation exception
1046 * @throws IllegalAccessException the illegal access exception
1047 * @throws IllegalArgumentException the illegal argument exception
1048 * @throws InvocationTargetException the invocation target exception
1049 * @throws NoSuchMethodException the no such method exception
1050 * @throws SecurityException the security exception
1052 private void simpleDbToObject(Introspector obj, Vertex v) {
1053 for (String key : obj.getProperties()) {
1054 this.copySimpleProperty(key, obj, v);
1058 public Map<String, Object> convertVertexToHashMap(Introspector obj, Vertex v) {
1060 long startTime = System.currentTimeMillis();
1062 Set<String> simpleProperties = obj.getSimpleProperties(PropertyPredicates.isVisible());
1063 String[] simplePropsArray = new String[simpleProperties.size()];
1064 simplePropsArray = simpleProperties.toArray(simplePropsArray);
1066 Map<String, Object> simplePropsHashMap = new HashMap<>(simplePropsArray.length * 2);
1068 v.properties(simplePropsArray).forEachRemaining((vp) -> simplePropsHashMap.put(vp.key(), vp.value()));
1070 return simplePropsHashMap;
1073 public Introspector dbToRelationshipObject(Vertex v) throws UnsupportedEncodingException, AAIException {
1074 Introspector relationshipList = this.latestLoader.introspectorFromName("relationship-list");
1075 relationshipList = createRelationshipList(v, relationshipList, "false");
1076 return relationshipList;
1080 * Creates the relationship list.
1083 * @param obj the obj
1084 * @param cleanUp the clean up
1085 * @return the object
1086 * @throws InstantiationException the instantiation exception
1087 * @throws IllegalAccessException the illegal access exception
1088 * @throws IllegalArgumentException the illegal argument exception
1089 * @throws InvocationTargetException the invocation target exception
1090 * @throws NoSuchMethodException the no such method exception
1091 * @throws SecurityException the security exception
1092 * @throws UnsupportedEncodingException the unsupported encoding exception
1093 * @throws AAIException the AAI exception
1094 * @throws MalformedURLException the malformed URL exception
1095 * @throws URISyntaxException
1097 private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp)
1098 throws UnsupportedEncodingException, AAIException {
1100 String[] cousinRules = new String[0];
1103 cousinRules = edgeRules.retrieveCachedCousinLabels(obj.getDbName());
1104 } catch (ExecutionException e) {
1105 LOGGER.warn("Encountered an execution exception while retrieving labels for the node type {} using cached",
1106 obj.getDbName(), e);
1109 List<Vertex> cousins = null;
1110 if (cousinRules != null && cousinRules.length != 0) {
1111 cousins = this.engine.getQueryEngine().findCousinVertices(v, cousinRules);
1113 cousins = this.engine.getQueryEngine().findCousinVertices(v);
1116 List<Object> relationshipObjList = obj.getValue("relationship");
1117 VertexProperty nodeTypeProperty = v.property(AAIProperties.NODE_TYPE);
1119 if (!nodeTypeProperty.isPresent()) {
1120 LoggingContext.responseDescription(MISSING_REQUIRED_NODE_PROPERTY);
1121 LOGGER.warn("Not processing the vertex {} because its missing required property aai-node-type", v.id());
1122 LoggingContext.remove(LoggingContext.LoggingField.RESPONSE_DESCRIPTION.toString());
1126 String aNodeType = nodeTypeProperty.value().toString();
1128 TypeAlphabetizer alphabetizer = new TypeAlphabetizer();
1130 EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class);
1131 Set<String> keysWithMultipleLabels = edgeIngestor.getMultipleLabelKeys();
1133 // For the given vertex, find all the cousins
1134 // For each cousin retrieve the node type and then
1135 // check if the version is greater than the edge label version
1136 // meaning is the current version equal to greater than the version
1137 // where we introduced the edge labels into the relationship payload
1138 // If it is, then we check if the edge key there are multiple labels
1139 // If there are multiple labels, then we need to go to the database
1140 // to retrieve the labels between itself and cousin vertex
1141 // If there is only single label between the edge a and b, then
1142 // we can retrieve what that is without going to the database
1143 // from using the edge rules json and get the edge rule out of it
1144 EdgeRuleQuery.Builder queryBuilder = new EdgeRuleQuery.Builder(aNodeType);
1145 for (Vertex cousin : cousins) {
1146 VertexProperty vertexProperty = cousin.property(AAIProperties.NODE_TYPE);
1147 String bNodeType = null;
1148 if (vertexProperty.isPresent()) {
1149 bNodeType = cousin.property(AAIProperties.NODE_TYPE).value().toString();
1151 // If the vertex is missing the aai-node-type
1152 // Then its either a bad vertex or its in the process
1153 // of getting deleted so we should ignore these vertexes
1154 LoggingContext.responseDescription(MISSING_REQUIRED_NODE_PROPERTY);
1155 if (LOGGER.isDebugEnabled()) {
1156 LOGGER.debug("For the vertex {}, unable to retrieve the aai-node-type", v.id().toString());
1158 LOGGER.info("Unable to retrieve the aai-node-type for vertex, for more info enable debug log");
1160 LoggingContext.remove(LoggingContext.LoggingField.RESPONSE_DESCRIPTION.toString());
1163 if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
1164 String edgeKey = alphabetizer.buildAlphabetizedKey(aNodeType, bNodeType);
1165 if (keysWithMultipleLabels.contains(edgeKey)) {
1166 List<String> edgeLabels = this.getEdgeLabelsBetween(EdgeType.COUSIN, v, cousin);
1167 for (String edgeLabel : edgeLabels) {
1168 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1169 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, edgeLabel);
1170 if (result != null) {
1171 relationshipObjList.add(result);
1176 EdgeRule edgeRule = null;
1178 // Create a query based on the a nodetype and b nodetype
1179 // which is also a cousin edge and ensure the version
1180 // is used properly so for example in order to be backwards
1181 // compatible if we had allowed a edge between a and b
1182 // in a previous release and we decided to remove it from
1183 // the edge rules in the future we can display the edge
1184 // only for the older apis and the new apis if the edge rule
1185 // is removed will not be seen in the newer version of the API
1187 EdgeRuleQuery ruleQuery =
1188 queryBuilder.to(bNodeType).edgeType(EdgeType.COUSIN).version(obj.getVersion()).build();
1191 edgeRule = edgeIngestor.getRule(ruleQuery);
1192 } catch (EdgeRuleNotFoundException e) {
1194 "Caught an edge rule not found exception for query {}, {},"
1195 + " it could be the edge rule is no longer valid for the existing edge in db",
1196 ruleQuery, LogFormatTools.getStackTop(e));
1198 } catch (AmbiguousRuleChoiceException e) {
1199 LOGGER.error("Caught an ambiguous rule not found exception for query {}, {}", ruleQuery,
1200 LogFormatTools.getStackTop(e));
1204 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1205 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, edgeRule.getLabel());
1206 if (result != null) {
1207 relationshipObjList.add(result);
1211 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
1212 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
1213 if (result != null) {
1214 relationshipObjList.add(result);
1220 if (relationshipObjList.isEmpty()) {
1228 * Process edge relationship.
1230 * @param relationshipObj the relationship obj
1231 * @param edge the edge
1232 * @param cleanUp the clean up
1233 * @return the object
1234 * @throws InstantiationException the instantiation exception
1235 * @throws IllegalAccessException the illegal access exception
1236 * @throws IllegalArgumentException the illegal argument exception
1237 * @throws InvocationTargetException the invocation target exception
1238 * @throws NoSuchMethodException the no such method exception
1239 * @throws SecurityException the security exception
1240 * @throws UnsupportedEncodingException the unsupported encoding exception
1241 * @throws AAIException the AAI exception
1242 * @throws MalformedURLException the malformed URL exception
1243 * @throws AAIUnknownObjectException
1244 * @throws URISyntaxException
1246 private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp,
1247 String edgeLabel) throws UnsupportedEncodingException, AAIUnknownObjectException {
1249 VertexProperty aaiUriProperty = cousin.property("aai-uri");
1251 if (!aaiUriProperty.isPresent()) {
1255 URI uri = UriBuilder.fromUri(aaiUriProperty.value().toString()).build();
1257 URIToRelationshipObject uriParser = null;
1258 Introspector result = null;
1260 uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
1261 result = uriParser.getResult();
1262 } catch (AAIException | URISyntaxException e) {
1263 LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion()
1264 + " (bad vertex ID=" + ": " + e.getMessage() + " " + LogFormatTools.getStackTop(e));
1268 VertexProperty cousinVertexNodeType = cousin.property(AAIProperties.NODE_TYPE);
1270 if (cousinVertexNodeType.isPresent()) {
1271 String cousinType = cousinVertexNodeType.value().toString();
1272 if (namedPropNodes.contains(cousinType)) {
1273 this.addRelatedToProperty(result, cousin, cousinType);
1277 if (edgeLabel != null && result.hasProperty("relationship-label")) {
1278 result.setValue("relationship-label", edgeLabel);
1281 return result.getUnderlyingObject();
1285 * Gets the URI for vertex.
1288 * @return the URI for vertex
1289 * @throws InstantiationException the instantiation exception
1290 * @throws IllegalAccessException the illegal access exception
1291 * @throws IllegalArgumentException the illegal argument exception
1292 * @throws InvocationTargetException the invocation target exception
1293 * @throws NoSuchMethodException the no such method exception
1294 * @throws SecurityException the security exception
1295 * @throws UnsupportedEncodingException the unsupported encoding exception
1296 * @throws AAIUnknownObjectException
1298 public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
1300 return getURIForVertex(v, false);
1303 public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
1304 URI uri = UriBuilder.fromPath("/unknown-uri").build();
1306 String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
1308 if (aaiUri != null && !overwrite) {
1309 uri = UriBuilder.fromPath(aaiUri).build();
1316 * Gets the URI from list.
1318 * @param list the list
1319 * @return the URI from list
1320 * @throws UnsupportedEncodingException the unsupported encoding exception
1322 private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
1324 StringBuilder sb = new StringBuilder();
1325 for (Introspector i : list) {
1326 sb.insert(0, i.getURI());
1329 uri = sb.toString();
1330 return UriBuilder.fromPath(uri).build();
1333 public void addRelatedToProperty(Introspector relationship, Vertex cousinVertex, String cousinType)
1334 throws AAIUnknownObjectException {
1336 Introspector obj = null;
1339 obj = this.loader.introspectorFromName(cousinType);
1340 } catch (AAIUnknownObjectException ex) {
1341 if (LOGGER.isTraceEnabled()) {
1342 LOGGER.trace("Encountered unknown object exception when trying to load nodetype of {} for vertex id {}",
1343 cousinType, cousinVertex.id());
1348 String nameProps = obj.getMetadata(ObjectMetadata.NAME_PROPS);
1349 List<Introspector> relatedToProperties = new ArrayList<>();
1351 if (nameProps != null) {
1352 String[] props = nameProps.split(",");
1353 for (String prop : props) {
1354 final Object temp = getProperty(obj, prop, cousinVertex);
1355 Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
1356 relatedTo.setValue("property-key", cousinType + "." + prop);
1357 relatedTo.setValue("property-value", temp);
1358 relatedToProperties.add(relatedTo);
1362 if (!relatedToProperties.isEmpty()) {
1363 List relatedToList = (List) relationship.getValue("related-to-property");
1364 for (Introspector introspector : relatedToProperties) {
1365 relatedToList.add(introspector.getUnderlyingObject());
1371 private Object getProperty(Introspector obj, String prop, Vertex vertex) {
1373 final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(prop);
1374 String dbPropertyName = prop;
1376 if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
1377 dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
1380 return vertex.<Object>property(dbPropertyName).orElse(null);
1386 * @param relationship the relationship
1387 * @param inputVertex the input vertex
1388 * @return true, if successful
1389 * @throws UnsupportedEncodingException the unsupported encoding exception
1390 * @throws AAIException the AAI exception
1392 public boolean createEdge(Introspector relationship, Vertex inputVertex)
1393 throws UnsupportedEncodingException, AAIException {
1395 Vertex relatedVertex = null;
1396 StopWatch.conditionalStart();
1397 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1399 String label = null;
1400 if (relationship.hasProperty("relationship-label")) {
1401 label = relationship.getValue("relationship-label");
1404 List<Vertex> results = parser.getQueryBuilder().toList();
1405 if (results.isEmpty()) {
1406 dbTimeMsecs += StopWatch.stopIfStarted();
1407 AAIException e = new AAIException("AAI_6129",
1408 "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
1409 e.getTemplateVars().add(parser.getResultType());
1410 e.getTemplateVars().add(parser.getUri().toString());
1413 // still an issue if there's more than one
1414 relatedVertex = results.get(0);
1417 if (relatedVertex != null) {
1421 e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1423 edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
1425 // attempted to link two vertexes already linked
1428 dbTimeMsecs += StopWatch.stopIfStarted();
1432 dbTimeMsecs += StopWatch.stopIfStarted();
1437 * Gets all the edges between of the type with the specified label.
1439 * @param aVertex the out vertex
1440 * @param bVertex the in vertex
1441 * @return the edges between
1442 * @throws AAIException the AAI exception
1443 * @throws NoEdgeRuleFoundException
1445 private Edge getEdgeBetweenWithLabel(EdgeType type, Vertex aVertex, Vertex bVertex, EdgeRule edgeRule) {
1449 if (bVertex != null) {
1450 GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1451 if (EdgeType.TREE.equals(type)) {
1452 GraphTraversal<Vertex, Vertex> findVertex = this.engine.asAdmin().getTraversalSource().V(bVertex);
1453 if (edgeRule.getDirection().equals(Direction.IN)) {
1454 findEdgesBetween = findVertex.outE(edgeRule.getLabel())
1455 .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains())
1456 .not(__.has(EdgeField.PRIVATE.toString(), true));
1458 findEdgesBetween = findVertex.inE(edgeRule.getLabel())
1459 .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains())
1460 .not(__.has(EdgeField.PRIVATE.toString(), true));
1462 findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(aVertex.id())).limit(1);
1464 findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(edgeRule.getLabel());
1465 findEdgesBetween = findEdgesBetween.has(EdgeProperty.CONTAINS.toString(), "NONE")
1466 .not(__.has(EdgeField.PRIVATE.toString(), true));
1467 findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id())).limit(1);
1469 List<Edge> list = findEdgesBetween.toList();
1470 if (!list.isEmpty()) {
1471 result = list.get(0);
1479 * Gets all the edges between of the type.
1481 * @param aVertex the out vertex
1482 * @param bVertex the in vertex
1483 * @return the edges between
1484 * @throws AAIException the AAI exception
1485 * @throws NoEdgeRuleFoundException
1487 private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
1489 List<Edge> result = new ArrayList<>();
1491 if (bVertex != null) {
1492 GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1493 findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
1494 if (EdgeType.TREE.equals(type)) {
1495 findEdgesBetween = findEdgesBetween.not(__.or(__.has(EdgeProperty.CONTAINS.toString(), "NONE"),
1496 __.has(EdgeField.PRIVATE.toString(), true)));
1498 findEdgesBetween = findEdgesBetween.has(EdgeProperty.CONTAINS.toString(), "NONE")
1499 .not(__.has(EdgeField.PRIVATE.toString(), true));
1501 findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
1502 result = findEdgesBetween.toList();
1509 * Gets all the edges string between of the type.
1511 * @param aVertex the out vertex
1512 * @param bVertex the in vertex
1513 * @return the edges between
1514 * @throws AAIException the AAI exception
1515 * @throws NoEdgeRuleFoundException
1517 private List<String> getEdgeLabelsBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
1519 List<String> result = new ArrayList<>();
1521 if (bVertex != null) {
1522 GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1523 findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
1524 if (EdgeType.TREE.equals(type)) {
1525 findEdgesBetween = findEdgesBetween.not(__.or(__.has(EdgeProperty.CONTAINS.toString(), "NONE"),
1526 __.has(EdgeField.PRIVATE.toString(), true)));
1528 findEdgesBetween = findEdgesBetween.has(EdgeProperty.CONTAINS.toString(), "NONE")
1529 .not(__.has(EdgeField.PRIVATE.toString(), true));
1531 findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
1532 result = findEdgesBetween.label().toList();
1538 * Gets all the edges string between of the type.
1540 * @param aVertex the out vertex
1541 * @param bVertex the in vertex
1542 * @return the edges between
1543 * @throws AAIException the AAI exception
1544 * @throws NoEdgeRuleFoundException
1546 private Long getEdgeLabelsCount(Vertex aVertex, Vertex bVertex) {
1550 if (bVertex != null) {
1551 GraphTraversal<Vertex, Edge> findEdgesBetween = null;
1552 findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
1553 findEdgesBetween = findEdgesBetween.has(EdgeProperty.CONTAINS.toString(), "NONE")
1554 .not(__.has(EdgeField.PRIVATE.toString(), true));
1555 findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
1556 result = findEdgesBetween.count().next();
1562 * Gets all the edges between the vertexes with the label and type.
1564 * @param aVertex the out vertex
1565 * @param bVertex the in vertex
1567 * @return the edges between
1568 * @throws AAIException the AAI exception
1570 private Edge getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1574 if (bVertex != null) {
1575 String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value();
1576 String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value();
1577 EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build();
1580 rule = edgeRules.getRule(q);
1581 } catch (EdgeRuleNotFoundException e) {
1582 throw new NoEdgeRuleFoundException(e);
1583 } catch (AmbiguousRuleChoiceException e) {
1584 throw new MultipleEdgeRuleFoundException(e);
1586 edge = this.getEdgeBetweenWithLabel(type, aVertex, bVertex, rule);
1593 * Gets the edge between with the label and edge type.
1595 * @param aVertex the out vertex
1596 * @param bVertex the in vertex
1598 * @return the edge between
1599 * @throws AAIException the AAI exception
1600 * @throws NoEdgeRuleFoundException
1602 public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
1604 StopWatch.conditionalStart();
1605 if (bVertex != null) {
1607 Edge edge = this.getEdgesBetween(type, aVertex, bVertex, label);
1609 dbTimeMsecs += StopWatch.stopIfStarted();
1614 dbTimeMsecs += StopWatch.stopIfStarted();
1618 public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
1619 return this.getEdgeBetween(type, aVertex, bVertex, null);
1625 * @param relationship the relationship
1626 * @param inputVertex the input vertex
1627 * @return true, if successful
1628 * @throws UnsupportedEncodingException the unsupported encoding exception
1629 * @throws AAIException the AAI exception
1631 public boolean deleteEdge(Introspector relationship, Vertex inputVertex)
1632 throws UnsupportedEncodingException, AAIException {
1634 Vertex relatedVertex = null;
1635 StopWatch.conditionalStart();
1636 QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
1638 List<Vertex> results = parser.getQueryBuilder().toList();
1640 String label = null;
1641 if (relationship.hasProperty("relationship-label")) {
1642 label = relationship.getValue("relationship-label");
1645 if (results.isEmpty()) {
1646 dbTimeMsecs += StopWatch.stopIfStarted();
1650 relatedVertex = results.get(0);
1653 edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
1654 } catch (NoEdgeRuleFoundException e) {
1655 dbTimeMsecs += StopWatch.stopIfStarted();
1656 throw new AAIException("AAI_6129", e);
1660 dbTimeMsecs += StopWatch.stopIfStarted();
1663 dbTimeMsecs += StopWatch.stopIfStarted();
1670 * Delete items with traversal.
1672 * @param vertexes the vertexes
1673 * @throws IllegalStateException the illegal state exception
1675 public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
1677 for (Vertex v : vertexes) {
1678 deleteWithTraversal(v);
1684 * Delete with traversal.
1686 * @param startVertex the start vertex
1688 public void deleteWithTraversal(Vertex startVertex) {
1689 StopWatch.conditionalStart();
1690 List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
1692 for (Vertex v : results) {
1693 LOGGER.debug("Removing vertex {} with label {}", v.id(), v.label());
1696 dbTimeMsecs += StopWatch.stopIfStarted();
1700 * Removes the list of vertexes from the graph
1702 * Current the vertex label will just be vertex but
1703 * in the future the aai-node-type property will be replaced
1704 * by using the vertex label as when retrieving an vertex
1705 * and retrieving an single property on an vertex will pre-fetch
1706 * all the properties of that vertex and this is due to the following property
1709 * query.fast-property=true
1712 * JanusGraph doesn't provide the capability to override that
1713 * at a transaction level and there is a plan to move to vertex label
1714 * so it is best to utilize this for now and when the change is applied
1716 * @param vertices - list of vertices to delete from the graph
1718 void delete(List<Vertex> vertices) {
1719 StopWatch.conditionalStart();
1721 for (Vertex v : vertices) {
1722 LOGGER.debug("Removing vertex {} with label {}", v.id(), v.label());
1726 dbTimeMsecs += StopWatch.stopIfStarted();
1733 * @param resourceVersion the resource version
1734 * @throws IllegalArgumentException the illegal argument exception
1735 * @throws AAIException the AAI exception
1736 * @throws InterruptedException the interrupted exception
1738 public void delete(Vertex v, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion)
1739 throws IllegalArgumentException, AAIException {
1741 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1743 * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain
1744 * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted
1745 * So its better to make these in 2 steps
1747 if (result && !deletableVertices.isEmpty()) {
1748 result = verifyPreventDeleteSemantics(deletableVertices);
1753 deleteWithTraversal(v);
1754 } catch (IllegalStateException e) {
1755 throw new AAIException("AAI_6110", e);
1766 * @param resourceVersion the resource version
1767 * @throws IllegalArgumentException the illegal argument exception
1768 * @throws AAIException the AAI exception
1769 * @throws InterruptedException the interrupted exception
1771 public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion)
1772 throws IllegalArgumentException, AAIException {
1774 boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
1779 deleteWithTraversal(v);
1780 } catch (IllegalStateException e) {
1781 throw new AAIException("AAI_6110", e);
1789 * Verify delete semantics.
1791 * @param vertex the vertex
1792 * @param resourceVersion the resource version
1793 * @return true, if successful
1794 * @throws AAIException the AAI exception
1796 private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion)
1797 throws AAIException {
1798 boolean result = true;
1799 String nodeType = "";
1800 String errorDetail = " unknown delete semantic found";
1801 String aaiExceptionCode = "";
1802 nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
1803 if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType,
1804 vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
1806 List<Vertex> vertices = new ArrayList<Vertex>();
1807 vertices.add(vertex);
1808 result = verifyPreventDeleteSemantics(vertices);
1814 * Verify Prevent delete semantics.
1816 * @param vertices the list of vertices
1817 * @return true, if successful
1818 * @throws AAIException the AAI exception
1820 private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException {
1821 boolean result = true;
1822 String nodeType = "";
1823 String errorDetail = " unknown delete semantic found";
1824 String aaiExceptionCode = "";
1826 StopWatch.conditionalStart();
1828 * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a
1829 * "prevent-delete" condition
1830 * If yes - that should prevent the deletion of the vertex
1831 * Dedup makes sure we dont capture the prevent-delete vertices twice
1832 * The prevent-delete vertices are stored so that the error message displays what prevents the delete
1835 List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices)
1836 .union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV()
1837 .values(AAIProperties.NODE_TYPE),
1838 __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV()
1839 .values(AAIProperties.NODE_TYPE))
1842 dbTimeMsecs += StopWatch.stopIfStarted();
1843 if (!preventDeleteVertices.isEmpty()) {
1844 aaiExceptionCode = "AAI_6110";
1845 errorDetail = String.format(
1846 "Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types %s",
1847 preventDeleteVertices);
1851 throw new AAIException(aaiExceptionCode, errorDetail);
1857 * Verify resource version.
1859 * @param action the action
1860 * @param nodeType the node type
1861 * @param currentResourceVersion the current resource version
1862 * @param resourceVersion the resource version
1863 * @param uri the uri
1864 * @return true, if successful
1865 * @throws AAIException the AAI exception
1867 public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion,
1868 String resourceVersion, String uri) throws AAIException {
1869 String enabled = "";
1870 String errorDetail = "";
1871 String aaiExceptionCode = "";
1872 boolean isDeleteResourceVersionOk = true;
1873 if (currentResourceVersion == null) {
1874 currentResourceVersion = "";
1877 if (resourceVersion == null) {
1878 resourceVersion = "";
1881 enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
1883 } catch (AAIException e) {
1884 ErrorLogHelper.logException(e);
1886 if (enabled.equals("true")) {
1887 if ("delete".equals(action)) {
1888 isDeleteResourceVersionOk = verifyResourceVersionForDelete(currentResourceVersion, resourceVersion);
1890 if ((!isDeleteResourceVersionOk)
1891 || ((!"delete".equals(action)) && (!currentResourceVersion.equals(resourceVersion)))) {
1892 if ("create".equals(action) && !resourceVersion.equals("")) {
1893 errorDetail = "resource-version passed for " + action + " of " + uri;
1894 aaiExceptionCode = "AAI_6135";
1895 } else if (resourceVersion.equals("")) {
1896 errorDetail = "resource-version not passed for " + action + " of " + uri;
1897 aaiExceptionCode = "AAI_6130";
1899 errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
1900 aaiExceptionCode = "AAI_6131";
1903 throw new AAIException(aaiExceptionCode, errorDetail);
1911 * Verify resource version for delete.
1913 * @param currentResourceVersion the current resource version
1914 * @param resourceVersion the resource version
1915 * @return true, if successful or false if there is a mismatch
1917 private boolean verifyResourceVersionForDelete(String currentResourceVersion, String resourceVersion) {
1919 boolean isDeleteResourceVersionOk = true;
1920 String resourceVersionDisabledUuid = AAIConfig.get(AAIConstants.AAI_RESVERSION_DISABLED_UUID,
1921 AAIConstants.AAI_RESVERSION_DISABLED_UUID_DEFAULT);
1923 if ((!currentResourceVersion.equals(resourceVersion))
1924 && (!resourceVersion.equals(resourceVersionDisabledUuid))) {
1925 isDeleteResourceVersionOk = false;
1927 return isDeleteResourceVersionOk;
1931 * Convert from camel case.
1933 * @param name the name
1934 * @return the string
1936 private String convertFromCamelCase(String name) {
1938 result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
1940 NamingExceptions exceptions = NamingExceptions.getInstance();
1941 result = exceptions.getDBName(result);
1946 private boolean canModify(Introspector obj, String propName, String requestContext) {
1947 final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
1948 if (readOnly != null) {
1949 final String[] items = readOnly.split(",");
1950 for (String item : items) {
1951 if (requestContext.equals(item)) {
1959 private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
1961 SideEffectRunner runner = new SideEffectRunner.Builder(this.engine, this).addSideEffect(DataCopy.class)
1962 .addSideEffect(PrivateEdge.class).build();
1964 runner.execute(obj, self);
1967 private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
1969 SideEffectRunner runner =
1970 new SideEffectRunner.Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
1972 runner.execute(obj, self);
1975 private void enrichData(Introspector obj, Vertex self) throws AAIException {
1977 SideEffectRunner runner =
1978 new SideEffectRunner.Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
1980 runner.execute(obj, self);
1983 public double getDBTimeMsecs() {
1984 return (dbTimeMsecs);
1988 * Db to object With Filters
1989 * This is for a one-time run with Tenant Isloation to only filter relationships
1990 * TODO: Chnage the original dbToObject to take filter parent/cousins
1992 * @param obj the obj
1993 * @param v the vertex from the graph
1994 * @param depth the depth
1995 * @param nodeOnly specify if to exclude relationships or not
1996 * @param filterCousinNodes
1997 * @return the introspector
1998 * @throws AAIException the AAI exception
1999 * @throws IllegalAccessException the illegal access exception
2000 * @throws IllegalArgumentException the illegal argument exception
2001 * @throws InvocationTargetException the invocation target exception
2002 * @throws SecurityException the security exception
2003 * @throws InstantiationException the instantiation exception
2004 * @throws NoSuchMethodException the no such method exception
2005 * @throws UnsupportedEncodingException the unsupported encoding exception
2006 * @throws MalformedURLException the malformed URL exception
2007 * @throws AAIUnknownObjectException
2008 * @throws URISyntaxException
2010 // TODO - See if you can merge the 2 dbToObjectWithFilters
2011 public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly,
2012 List<String> filterCousinNodes, List<String> filterParentNodes)
2013 throws AAIException, UnsupportedEncodingException {
2014 String cleanUp = "false";
2020 boolean modified = false;
2021 for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
2022 List<Object> getList = null;
2023 Vertex[] vertices = null;
2025 if (!(obj.isComplexType(property) || obj.isListType(property))) {
2026 this.copySimpleProperty(property, obj, v);
2029 if (obj.isComplexType(property)) {
2030 /* container case */
2032 if (!property.equals("relationship-list") && depth >= 0) {
2033 Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
2034 Object result = dbToObjectWithFilters(argumentObject, v, seen, depth + 1, nodeOnly,
2035 filterCousinNodes, filterParentNodes);
2036 if (result != null) {
2037 obj.setValue(property, argumentObject.getUnderlyingObject());
2040 } else if (property.equals("relationship-list") && !nodeOnly) {
2041 /* relationships need to be handled correctly */
2042 Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
2044 createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
2045 if (relationshipList != null) {
2047 obj.setValue(property, relationshipList.getUnderlyingObject());
2052 } else if (obj.isListType(property)) {
2054 if (property.equals("any")) {
2057 String genericType = obj.getGenericTypeClass(property).getSimpleName();
2058 if (obj.isComplexGenericType(property) && depth >= 0) {
2059 final String childDbName = convertFromCamelCase(genericType);
2060 String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
2063 boolean isthisParentRequired =
2064 filterParentNodes.parallelStream().anyMatch(childDbName::contains);
2066 EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build();
2069 rule = edgeRules.getRule(q);
2070 } catch (EdgeRuleNotFoundException e) {
2071 throw new NoEdgeRuleFoundException(e);
2072 } catch (AmbiguousRuleChoiceException e) {
2073 throw new MultipleEdgeRuleFoundException(e);
2075 if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
2076 // vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(),
2078 Direction ruleDirection = rule.getDirection();
2079 Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
2080 List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr);
2081 itr = verticesList.stream().filter(item -> {
2082 return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
2084 if (itr.hasNext()) {
2085 getList = (List<Object>) obj.getValue(property);
2089 while (itr.hasNext()) {
2090 Vertex childVertex = itr.next();
2091 if (!seen.contains(childVertex)) {
2092 Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
2094 Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth,
2095 nodeOnly, filterCousinNodes, filterParentNodes);
2096 if (result != null) {
2097 getList.add(argumentObject.getUnderlyingObject());
2103 LOGGER.warn("Cycle found while serializing vertex id={}",
2104 childVertex.id().toString());
2107 if (processed == 0) {
2108 // vertices were all seen, reset the list
2111 if (processed > 0) {
2115 } else if (obj.isSimpleGenericType(property)) {
2116 List<Object> temp = this.engine.getListProperty(v, property);
2118 getList = (List<Object>) obj.getValue(property);
2119 getList.addAll(temp);
2130 // no changes were made to this obj, discard the instance
2134 this.enrichData(obj, v);
2140 * Creates the relationship list with the filtered node types.
2143 * @param obj the obj
2144 * @param cleanUp the clean up
2145 * @return the object
2146 * @throws InstantiationException the instantiation exception
2147 * @throws IllegalAccessException the illegal access exception
2148 * @throws IllegalArgumentException the illegal argument exception
2149 * @throws InvocationTargetException the invocation target exception
2150 * @throws NoSuchMethodException the no such method exception
2151 * @throws SecurityException the security exception
2152 * @throws UnsupportedEncodingException the unsupported encoding exception
2153 * @throws AAIException the AAI exception
2154 * @throws MalformedURLException the malformed URL exception
2155 * @throws URISyntaxException
2157 private Introspector createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp,
2158 List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
2159 List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
2161 Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
2162 String node = (String) item.property(AAIProperties.NODE_TYPE).orElse("");
2163 return filterNodes.parallelStream().anyMatch(node::contains);
2166 List<Vertex> cousins = (List<Vertex>) IteratorUtils.toList(cousinVertices);
2168 // items.parallelStream().anyMatch(inputStr::contains)
2169 List<Object> relationshipObjList = obj.getValue("relationship");
2170 for (Vertex cousin : cousins) {
2172 Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
2173 Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
2174 if (result != null) {
2175 relationshipObjList.add(result);
2180 if (relationshipObjList.isEmpty()) {