summaryrefslogtreecommitdiffstats
path: root/aai-core/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'aai-core/src/main/java')
-rw-r--r--aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java4
-rw-r--r--aai-core/src/main/java/org/onap/aai/introspection/Introspector.java182
-rw-r--r--aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java82
-rw-r--r--aai-core/src/main/java/org/onap/aai/introspection/Loader.java25
-rw-r--r--aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java36
-rw-r--r--aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java103
-rw-r--r--aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java299
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java3736
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java51
-rw-r--r--aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java57
10 files changed, 2481 insertions, 2094 deletions
diff --git a/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java b/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java
index aa4ec1a1..e737f08d 100644
--- a/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java
+++ b/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java
@@ -21,14 +21,16 @@
*/
package org.onap.aai.config;
+import org.onap.aai.schema.enums.ObjectMetadata;
import org.onap.aai.setup.SchemaVersion;
import org.onap.aai.setup.SchemaVersions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import java.util.Map;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
import org.onap.aai.introspection.LoaderFactory;
import org.onap.aai.introspection.MoxyLoader;
diff --git a/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java b/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java
index c7520dd4..269d6330 100644
--- a/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java
+++ b/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java
@@ -36,6 +36,7 @@ import org.onap.aai.workarounds.NamingExceptions;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
+import java.util.stream.Collectors;
public abstract class Introspector implements Cloneable {
@@ -57,25 +58,25 @@ public abstract class Introspector implements Cloneable {
protected String convertPropertyName (String name) {
return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name);
}
-
+
protected abstract Object get(String name);
protected abstract void set(String name, Object value);
/**
- *
+ *
* @param name the property name you'd like to retrieve the value for
* @return the value of the property
*/
public <T> T getValue(String name) {
String convertedName = convertPropertyName(name);
Object result = null;
-
+
if (this.hasProperty(name)) {
result = this.get(convertedName);
} else {
/* property not found - slightly ambiguous */
return null;
}
-
+
Class<?> clazz = this.getClass(name);
if (this.isListType(name) && result == null) {
try {
@@ -88,18 +89,18 @@ public abstract class Introspector implements Cloneable {
return (T)result;
}
-
+
public Introspector getWrappedValue(String name) {
String convertedName = convertPropertyName(name);
Object value = null;
-
+
if (this.hasProperty(name)) {
value = this.get(convertedName);
} else {
/* property not found - slightly ambiguous */
return null;
}
-
+
Class<?> clazz = this.getClass(name);
if (this.isListType(name) && value == null) {
try {
@@ -115,9 +116,9 @@ public abstract class Introspector implements Cloneable {
//no value
return null;
}
-
+
}
-
+
public List<Introspector> getWrappedListValue(String name) {
String convertedName = convertPropertyName(name);
Object value = null;
@@ -141,17 +142,17 @@ public abstract class Introspector implements Cloneable {
LOGGER.warn(e.getMessage(),e);
}
}
-
+
List<Object> valueList = (List<Object>)value;
-
+
for (Object item : valueList) {
resultList.add(IntrospectorFactory.newInstance(this.getModelType(), item));
}
-
+
return resultList;
-
+
}
-
+
public Object castValueAccordingToSchema(String name, Object obj) {
Object result = obj;
Class<?> nameClass = this.getClass(name);
@@ -159,11 +160,11 @@ public abstract class Introspector implements Cloneable {
throw new IllegalArgumentException("property: " + name + " does not exist on " + this.getDbName());
}
if (obj != null) {
-
+
try {
if (!obj.getClass().getName().equals(nameClass.getName())) {
if (nameClass.isPrimitive()) {
- nameClass = ClassUtils.primitiveToWrapper(nameClass);
+ nameClass = ClassUtils.primitiveToWrapper(nameClass);
result = nameClass.getConstructor(String.class).newInstance(obj.toString());
}
if (obj instanceof String) {
@@ -180,35 +181,35 @@ public abstract class Introspector implements Cloneable {
}
return result;
}
-
+
public List<Object> castValueAccordingToSchema(String name, List<?> objs) {
List<Object> result = new ArrayList<>();
-
+
for (Object item : objs) {
result.add(this.castValueAccordingToSchema(name, item));
}
-
+
return result;
-
+
}
/**
- *
+ *
* @param name the property name you'd like to set the value of
* @param obj the value to be set
* @return
*/
public void setValue(String name, Object obj) throws IllegalArgumentException {
Object box = this.castValueAccordingToSchema(name, obj);
-
+
name = convertPropertyName(name);
this.set(name, box);
}
/**
- *
+ *
* @return a list of all the properties available on the object
*/
public abstract Set<String> getProperties();
-
+
public Set<String> getProperties(PropertyPredicate<Introspector, String> p) {
final Set<String> temp = new LinkedHashSet<>();
this.getProperties().stream().filter(item -> {
@@ -217,22 +218,30 @@ public abstract class Introspector implements Cloneable {
temp.add(item);
});
final Set<String> result = Collections.unmodifiableSet(temp);
-
+
return result;
-
+
}
+
+ public Set<String> getSimpleProperties(PropertyPredicate<Introspector, String> p){
+ return this.getProperties()
+ .stream()
+ .filter(item -> p.test(this, item))
+ .filter(this::isSimpleType)
+ .collect(Collectors.toSet());
+ }
/**
- *
+ *
* @return a list of the required properties on the object
*/
public abstract Set<String> getRequiredProperties();
/**
- *
+ *
* @return a list of the properties that can be used to query the object in the db
*/
public abstract Set<String> getKeys();
/**
- *
+ *
* @return a list of the all key properties for this object
*/
public Set<String> getAllKeys() {
@@ -274,7 +283,7 @@ public abstract class Introspector implements Cloneable {
result = this.indexedProperties;
return result;
}
-
+
public Set<String> getUniqueProperties() {
Set<String> result = null;
if (this.uniqueProperties == null) {
@@ -292,7 +301,7 @@ public abstract class Introspector implements Cloneable {
result = this.uniqueProperties;
return result;
}
-
+
public Set<String> getDependentOn() {
String dependentOn = this.getMetadata(ObjectMetadata.DEPENDENT_ON);
if (dependentOn == null) {
@@ -301,21 +310,21 @@ public abstract class Introspector implements Cloneable {
return new LinkedHashSet<>(Arrays.asList(dependentOn.split(",")));
}
/**
- *
+ *
* @param name
* @return the string name of the java class of the named property
*/
public String getType(String name) {
Class<?> resultClass = this.getClass(name);
String result = "";
-
+
if (resultClass != null) {
result = resultClass.getName();
if (result.equals("java.util.ArrayList")) {
result = "java.util.List";
}
}
-
+
return result;
}
/**
@@ -327,33 +336,33 @@ public abstract class Introspector implements Cloneable {
public String getGenericType(String name) {
Class<?> resultClass = this.getGenericTypeClass(name);
String result = "";
-
+
if (resultClass != null) {
result = resultClass.getName();
}
-
+
return result;
}
/**
- *
+ *
* @return the string name of the java class of the underlying object
*/
public abstract String getJavaClassName();
-
+
/**
- *
+ *
* @param name the property name
* @return the Class object
*/
public abstract Class<?> getClass(String name);
-
+
public abstract Class<?> getGenericTypeClass(String name);
/**
- *
+ *
* @param name the property name
* @return a new instance of the underlying type of this property
- * @throws AAIUnknownObjectException
+ * @throws AAIUnknownObjectException
*/
public Object newInstanceOfProperty(String name) throws AAIUnknownObjectException {
String type = this.getType(name);
@@ -364,22 +373,22 @@ public abstract class Introspector implements Cloneable {
String type = this.getGenericType(name);
return loader.objectFromName(type);
}
-
-
+
+
public Introspector newIntrospectorInstanceOfProperty(String name) throws AAIUnknownObjectException {
-
+
Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfProperty(name));
-
+
return result;
-
+
}
-
+
public Introspector newIntrospectorInstanceOfNestedProperty(String name) throws AAIUnknownObjectException {
-
+
Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfNestedProperty(name));
-
+
return result;
-
+
}
/**
* Is this type not a Java String or primitive
@@ -388,56 +397,56 @@ public abstract class Introspector implements Cloneable {
*/
public boolean isComplexType(String name) {
String result = this.getType(name);
-
+
if (result.contains("aai") || result.equals("java.lang.Object")) {
return true;
} else {
return false;
}
}
-
+
public boolean isComplexGenericType(String name) {
String result = this.getGenericType(name);
-
+
if (result.contains("aai")) {
return true;
} else {
return false;
}
}
-
+
public boolean isSimpleType(String name) {
return !(this.isComplexType(name) || this.isListType(name));
}
-
+
public boolean isSimpleGenericType(String name) {
return !this.isComplexGenericType(name);
}
public boolean isListType(String name) {
String result = this.getType(name);
-
+
if (result.contains("java.util.List")) {
return true;
} else {
return false;
}
}
-
+
public boolean isContainer() {
Set<String> props = this.getProperties();
boolean result = false;
if (props.size() == 1 && this.isListType(props.iterator().next())) {
result = true;
}
-
+
return result;
}
-
+
public abstract String getChildName();
public String getChildDBName() {
String result = this.getChildName();
-
+
result = namingException.getDBName(result);
return result;
}
@@ -447,10 +456,10 @@ public abstract class Introspector implements Cloneable {
String lowerHyphen = this.getName();
lowerHyphen = namingException.getDBName(lowerHyphen);
-
+
return lowerHyphen;
}
-
+
public abstract ModelType getModelType();
public boolean hasChild(Introspector child) {
@@ -474,7 +483,7 @@ public abstract class Introspector implements Cloneable {
}
return result;
}
-
+
public void setURIChain(String uri) {
this.uriChain = uri;
}
@@ -488,21 +497,21 @@ public abstract class Introspector implements Cloneable {
if (this.isContainer()) {
result += "/" + this.getName();
} else {
-
+
if (container != null) {
result += "/" + container;
}
result += "/" + this.getDbName() + "/" + this.findKey();
-
+
if (namespace != null && !namespace.equals("")) {
result = "/" + namespace + result;
}
}
-
+
return result;
}
-
+
public String getGenericURI() {
String result = "";
if (this.isContainer()) {
@@ -513,10 +522,10 @@ public abstract class Introspector implements Cloneable {
result += "/{" + this.getDbName() + "-" + key + "}";
}
}
-
+
return result;
}
-
+
public String getFullGenericURI() {
String result = "";
String namespace = this.getMetadata(ObjectMetadata.NAMESPACE);
@@ -537,33 +546,33 @@ public abstract class Introspector implements Cloneable {
if (namespace != null && !namespace.equals("")) {
result = "/" + namespace + result;
}
-
+
}
-
+
return result;
}
public abstract String preProcessKey(String key);
-
+
protected abstract String findKey() throws UnsupportedEncodingException;
-
+
public abstract String marshal(MarshallerProperties properties);
-
+
public abstract Object clone();
public abstract Object getUnderlyingObject();
-
+
public String marshal(boolean formatted) {
MarshallerProperties properties =
new MarshallerProperties.Builder(MediaType.APPLICATION_JSON_TYPE).formatted(formatted).build();
-
+
return marshal(properties);
}
public String makeSingular(String word) {
-
+
String result = word;
result = result.replaceAll("(?:([ho])es|s)$", "");
-
+
if (result.equals("ClassesOfService")) {
result = "ClassOfService";
} else if (result.equals("CvlanTag")) {
@@ -573,10 +582,10 @@ public abstract class Introspector implements Cloneable {
}
return result;
}
-
+
protected String makePlural(String word) {
String result = word;
-
+
if (result.equals("cvlan-tag-entry")) {
return "cvlan-tags";
} else if (result.equals("class-of-service")) {
@@ -590,7 +599,7 @@ public abstract class Introspector implements Cloneable {
if (result.equals("classes-of-services")) {
result = "classes-of-service";
}*/
-
+
return result;
}
@@ -599,21 +608,22 @@ public abstract class Introspector implements Cloneable {
public Optional<String> getPropertyMetadata(String propName, PropertyMetadata metadataName) {
final String resultValue = this.getPropertyMetadata(propName).getOrDefault(metadataName, "");
Optional<String> result = Optional.empty();
-
+
if (!resultValue.isEmpty()) {
result = Optional.of(resultValue);
}
return result;
-
+
}
public abstract SchemaVersion getVersion();
public Loader getLoader() {
return this.loader;
}
-
+
public boolean isTopLevel() {
-
+
return this.getMetadata(ObjectMetadata.NAMESPACE) != null;
}
+
}
diff --git a/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java b/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java
index b1447d8f..d54a9833 100644
--- a/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java
+++ b/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java
@@ -46,47 +46,47 @@ public class JSONStrategy extends Introspector {
throw new IllegalArgumentException("This object has no named type.");
}
}
-
+
protected JSONStrategy(Object o, String namedType) {
super(o);
json = (JSONObject)o;
this.namedType = namedType;
-
+
}
-
+
@Override
public boolean hasProperty(String name) {
- //TODO
+ //TODO
return true;
}
@Override
public Object getValue(String name) {
Object result = "";
result = json.get(name);
-
+
return result;
}
@Override
public void setValue(String name, Object obj) {
json.put(name, obj);
-
+
}
@Override
public Object getUnderlyingObject() {
return this.json;
}
-
+
@Override
public Set<String> getProperties() {
Set<String> result = json.keySet();
return result;
}
-
+
@Override
public Set<String> getRequiredProperties() {
//unknowable
-
+
return this.getProperties();
}
@@ -109,11 +109,11 @@ public class JSONStrategy extends Introspector {
if (resultClass != null) {
result = resultClass.getName();
}
-
+
if (result.equals("org.json.simple.JSONArray")) {
result = "java.util.List";
}
-
+
return result;
}
@@ -136,7 +136,7 @@ public class JSONStrategy extends Introspector {
public Class<?> getClass(String name) {
Class<?> result = null;
result = json.get(name).getClass();
-
+
return result;
}
@@ -148,7 +148,7 @@ public class JSONStrategy extends Introspector {
if (resultObject.getClass().getName().equals("org.json.simple.JSONArray")) {
resultClass = ((List)resultObject).get(0).getClass();
}
-
+
return resultClass;
}
@@ -169,43 +169,43 @@ public class JSONStrategy extends Introspector {
return null;
}
}
-
+
@Override
public boolean isComplexType(String name) {
String result = this.getType(name);
-
+
if (result.contains("JSONObject")) {
return true;
} else {
return false;
}
-
+
}
-
+
@Override
public boolean isComplexGenericType(String name) {
String result = this.getGenericType(name);
-
+
if (result.contains("JSONObject")) {
return true;
} else {
return false;
}
-
+
}
-
+
@Override
public boolean isListType(String name) {
String result = this.getType(name);
-
+
if (result.contains("java.util.List")) {
return true;
} else {
return false;
}
-
+
}
-
+
@Override
public boolean isContainer() {
Set<String> props = this.getProperties();
@@ -213,66 +213,66 @@ public class JSONStrategy extends Introspector {
if (props.size() == 1 && this.isListType(props.iterator().next())) {
result = true;
}
-
+
return result;
}
@Override
protected String findKey() {
return "";
}
-
+
@Override
public String getName() {
return this.namedType;
}
-
+
@Override
public String getDbName() {
return this.getName();
}
-
+
@Override
public String getURI() {
-
- // use a UUID for now
+
+ // use a UUID for now
return UUID.randomUUID().toString();
}
-
+
@Override
public String getGenericURI() {
-
+
//there is none defined for this
return "";
}
-
+
@Override
public String preProcessKey (String key) {
-
+
// don't do anything with it
return key;
-
+
}
-
+
@Override
public String marshal(MarshallerProperties properties) {
//TODO
return null;
}
-
+
@Override
public Object clone() {
//TODO
return null;
}
-
+
/*@Override
public String findEdgeName(String parent, String child) {
-
+
// Always has for now
return "has";
-
+
}*/
-
+
@Override
public ModelType getModelType() {
return ModelType.JSON;
@@ -341,7 +341,7 @@ public class JSONStrategy extends Introspector {
@Override
protected void set(String name, Object value) {
// TODO Auto-generated method stub
-
+
}
@Override
diff --git a/aai-core/src/main/java/org/onap/aai/introspection/Loader.java b/aai-core/src/main/java/org/onap/aai/introspection/Loader.java
index 3a69e56e..cae4cbb7 100644
--- a/aai-core/src/main/java/org/onap/aai/introspection/Loader.java
+++ b/aai-core/src/main/java/org/onap/aai/introspection/Loader.java
@@ -25,12 +25,13 @@ import org.onap.aai.restcore.MediaType;
import org.onap.aai.setup.SchemaVersion;
import java.util.Map;
+import java.util.Set;
public abstract class Loader {
private final SchemaVersion version;
private final ModelType modelType;
-
+
/**
* Instantiates a new loader.
*
@@ -41,32 +42,32 @@ public abstract class Loader {
this.version = version;
this.modelType = modelType;
}
-
+
/**
* Process.
*
* @param version the version
*/
protected abstract void process(SchemaVersion version);
-
+
/**
* Object from name.
*
* @param name the name
* @return the object
- * @throws AAIUnknownObjectException
+ * @throws AAIUnknownObjectException
*/
public abstract Object objectFromName(String name) throws AAIUnknownObjectException;
-
+
/**
* Introspector from name.
*
* @param name the name
* @return the introspector
- * @throws AAIUnknownObjectException
+ * @throws AAIUnknownObjectException
*/
public abstract Introspector introspectorFromName(String name) throws AAIUnknownObjectException;
-
+
/**
* Unmarshal.
*
@@ -76,7 +77,7 @@ public abstract class Loader {
* @return the introspector
*/
public abstract Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException;
-
+
/**
* Unmarshal.
*
@@ -88,7 +89,7 @@ public abstract class Loader {
return unmarshal(type, json, MediaType.APPLICATION_JSON_TYPE);
}
-
+
/**
* Gets the model type.
*
@@ -97,7 +98,7 @@ public abstract class Loader {
public ModelType getModelType() {
return this.modelType;
}
-
+
/**
* Gets the version.
*
@@ -106,6 +107,8 @@ public abstract class Loader {
public SchemaVersion getVersion() {
return this.version;
}
-
+
public abstract Map<String, Introspector> getAllObjects();
+
+ public abstract Set<String> getNamedPropNodes();
}
diff --git a/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java b/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java
index 82504550..fa52d62f 100644
--- a/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java
+++ b/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java
@@ -34,6 +34,7 @@ import org.onap.aai.logging.ErrorLogHelper;
import org.onap.aai.logging.LogFormatTools;
import org.onap.aai.nodes.NodeIngestor;
import org.onap.aai.restcore.MediaType;
+import org.onap.aai.schema.enums.ObjectMetadata;
import org.onap.aai.setup.SchemaVersion;
import org.onap.aai.workarounds.NamingExceptions;
import org.springframework.stereotype.Component;
@@ -44,6 +45,7 @@ import java.io.*;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.stream.Collectors;
public class MoxyLoader extends Loader {
@@ -52,9 +54,11 @@ public class MoxyLoader extends Loader {
private Map<String, Introspector> allObjs = null;
private Map<SchemaVersion, MoxyLoader> moxyLoaderFactory;
-
+
private NodeIngestor nodeIngestor;
+ private Set<String> namedProps;
+
public MoxyLoader(SchemaVersion version, NodeIngestor nodeIngestor) {
super(version, ModelType.MOXY);
this.nodeIngestor = nodeIngestor;
@@ -67,14 +71,14 @@ public class MoxyLoader extends Loader {
}
/**
* {@inheritDoc}
- * @throws AAIUnknownObjectException
+ * @throws AAIUnknownObjectException
*/
@Override
public Introspector introspectorFromName(String name) throws AAIUnknownObjectException {
return IntrospectorFactory.newInstance(ModelType.MOXY, objectFromName(name));
}
-
+
/**
* {@inheritDoc}
*/
@@ -93,7 +97,7 @@ public class MoxyLoader extends Loader {
} else {
upperCamel = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, sanitizedName);
}
-
+
try {
final DynamicEntity result = jaxbContext.newDynamicEntity(upperCamel);
@@ -115,14 +119,14 @@ public class MoxyLoader extends Loader {
* We need to have just same JaxbContext for each version
*/
jaxbContext = nodeIngestor.getContextForVersion(version);
-
+
}
/**
* {@inheritDoc}
*/
@Override
- public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException {
+ public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException {
try {
final Object clazz = objectFromName(type);
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
@@ -143,7 +147,7 @@ public class MoxyLoader extends Loader {
throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), e);
}
}
-
+
@Override
public Map<String, Introspector> getAllObjects() {
if (this.allObjs != null) {
@@ -163,7 +167,7 @@ public class MoxyLoader extends Loader {
return allObjs;
}
}
-
+
private Set<String> objectsInVersion() {
Set<String> result = new HashSet<>();
@@ -177,7 +181,21 @@ public class MoxyLoader extends Loader {
//result.remove("EdgePropNames");
return result;
}
-
+
+ @Override
+ public Set<String> getNamedPropNodes(){
+
+ if(namedProps == null){
+ namedProps = getAllObjects()
+ .entrySet()
+ .stream()
+ .filter(
+ (entry) -> entry.getValue().getMetadata(ObjectMetadata.NAME_PROPS) != null
+ ).map(entry -> entry.getKey()).collect(Collectors.toSet());
+ }
+
+ return namedProps;
+ }
public DynamicJAXBContext getJAXBContext() {
return this.jaxbContext;
}
diff --git a/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java b/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java
index ecf31253..f0d487e8 100644
--- a/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java
+++ b/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java
@@ -51,9 +51,10 @@ import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.Map.Entry;
+import java.util.stream.Collectors;
public class MoxyStrategy extends Introspector {
-
+
private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(MoxyStrategy.class);
private DynamicEntity internalObject = null;
private DynamicType internalType = null;
@@ -67,9 +68,9 @@ public class MoxyStrategy extends Introspector {
private Set<String> requiredProperties = null;
private boolean isInitialized = false;
-
+
private NodeIngestor nodeIngestor;
-
+
protected MoxyStrategy(Object obj) {
super(obj);
/* must look up the correct jaxbcontext for this object */
@@ -81,19 +82,19 @@ public class MoxyStrategy extends Introspector {
jaxbContext = nodeIngestor.getContextForVersion(version);
String simpleName = internalObject.getClass().getName();
internalType = jaxbContext.getDynamicType(simpleName);
-
+
cd = internalType.getDescriptor();
try {
marshaller = jaxbContext.createMarshaller();
-
+
unmarshaller = jaxbContext.createUnmarshaller();
-
+
} catch (JAXBException e) {
}
}
-
+
private void init() {
isInitialized = true;
@@ -104,13 +105,13 @@ public class MoxyStrategy extends Introspector {
}
props = Collections.unmodifiableSet(props);
this.properties = props;
-
+
Set<String> requiredProps = new LinkedHashSet<>();
requiredProps = new LinkedHashSet<>();
for (DatabaseMapping dm : cd.getMappings()) {
- if (dm.getField() instanceof XMLField) {
+ if (dm.getField() instanceof XMLField) {
XMLField x = (XMLField)dm.getField();
- if (x != null) {
+ if (x != null) {
if (x.isRequired()) {
requiredProps.add(this.removeXPathDescriptor(x.getName()));
}
@@ -119,25 +120,25 @@ public class MoxyStrategy extends Introspector {
}
requiredProps = Collections.unmodifiableSet(requiredProps);
this.requiredProperties = requiredProps;
-
+
Set<String> keys = new LinkedHashSet<>();
-
+
for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) {
keys.add(this.removeXPathDescriptor(name));
}
keys = Collections.unmodifiableSet(keys);
this.keys = keys;
-
-
+
+
}
-
+
@Override
public boolean hasProperty(String name) {
String convertedName = convertPropertyName(name);
- return internalType.containsProperty(convertedName);
+ return internalType.containsProperty(convertedName);
}
-
+
@Override
public Object get(String name) {
return internalObject.get(name);
@@ -145,7 +146,7 @@ public class MoxyStrategy extends Introspector {
@Override
public void set(String name, Object obj) throws IllegalArgumentException {
-
+
internalObject.set(name, obj);
}
@@ -157,7 +158,7 @@ public class MoxyStrategy extends Introspector {
}
return this.properties;
-
+
}
@Override
@@ -179,7 +180,7 @@ public class MoxyStrategy extends Introspector {
return this.keys;
}
-
+
@Override
public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
String propName = this.convertPropertyName(prop);
@@ -192,7 +193,7 @@ public class MoxyStrategy extends Introspector {
PropertyMetadata.valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, (String)entry.getKey())), (String)entry.getValue());
}
}
-
+
return result;
}
@@ -200,8 +201,8 @@ public class MoxyStrategy extends Introspector {
public String getJavaClassName() {
return internalObject.getClass().getName();
}
-
-
+
+
@Override
public Class<?> getClass(String name) {
@@ -211,7 +212,7 @@ public class MoxyStrategy extends Introspector {
if (internalType.getPropertyType(name) == null) {
if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
-
+
} else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
} else {
@@ -243,7 +244,7 @@ public class MoxyStrategy extends Introspector {
resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass();
}
}
-
+
return resultClass;
}
@@ -251,20 +252,20 @@ public class MoxyStrategy extends Introspector {
public Object getUnderlyingObject() {
return this.internalObject;
}
-
+
@Override
public String getChildName() {
-
+
String className = internalObject.getClass().getSimpleName();
String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
-
+
if (this.isContainer()) {
lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName());
}
-
+
return lowerHyphen;
}
-
+
@Override
public String getName() {
String className = internalObject.getClass().getSimpleName();
@@ -273,11 +274,11 @@ public class MoxyStrategy extends Introspector {
if (this.isContainer()) {
lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().get(0)).getSimpleName());
}*/
-
+
return lowerHyphen;
}
-
+
@Override
public String getObjectId() throws UnsupportedEncodingException {
String result = "";
@@ -285,17 +286,17 @@ public class MoxyStrategy extends Introspector {
if (this.isContainer()) {
result += "/" + this.getName();
} else {
-
+
if (container != null) {
result += "/" + container;
}
result += "/" + this.getDbName() + "/" + this.findKey();
-
+
}
-
+
return result;
}
-
+
@Override
protected String findKey() throws UnsupportedEncodingException {
Set<String> keys = null;
@@ -305,10 +306,10 @@ public class MoxyStrategy extends Introspector {
String value = UriUtils.encode(this.getValue(key).toString(), "UTF-8");
results.add(value);
}
-
+
return Joiner.on("/").join(results);
}
-
+
@Override
public String preProcessKey (String key) {
String result = "";
@@ -316,19 +317,19 @@ public class MoxyStrategy extends Introspector {
String[] split = key.split("/");
int i = 0;
for (i = split.length-1; i >= 0; i--) {
-
+
if (jaxbContext.getDynamicType(split[i]) != null) {
break;
-
+
}
-
+
}
result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
-
+
return result;
-
+
}
-
+
@Override
public String marshal(MarshallerProperties properties) {
StringWriter result = new StringWriter();
@@ -339,7 +340,7 @@ public class MoxyStrategy extends Introspector {
marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName());
marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
}
-
+
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
marshaller.marshal(this.internalObject, result);
} catch (JAXBException e) {
@@ -348,7 +349,7 @@ public class MoxyStrategy extends Introspector {
return result.toString();
}
-
+
@Override
public Object clone() {
Object result = null;
@@ -358,7 +359,7 @@ public class MoxyStrategy extends Introspector {
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
-
+
result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue();
} catch (JAXBException e) {
// TODO Auto-generated catch block
@@ -371,21 +372,21 @@ public class MoxyStrategy extends Introspector {
public ModelType getModelType() {
return ModelType.MOXY;
}
-
+
private String removeXPathDescriptor(String name) {
-
+
return name.replaceAll("/text\\(\\)", "");
}
@Override
public String getMetadata(ObjectMetadata name) {
-
+
return (String)cd.getProperty(name.toString());
}
@Override
public SchemaVersion getVersion() {
-
+
return this.version;
}
}
diff --git a/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java b/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java
index dd5d42c6..bd7f1b91 100644
--- a/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java
+++ b/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java
@@ -8,7 +8,7 @@
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -50,6 +50,7 @@ import com.github.fge.jsonpatch.mergepatch.JsonMergePatch;
import org.apache.commons.lang.StringUtils;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
import org.janusgraph.core.JanusGraphException;
import org.javatuples.Pair;
import org.onap.aai.db.props.AAIProperties;
@@ -67,6 +68,7 @@ import org.onap.aai.nodes.NodeIngestor;
import org.onap.aai.parsers.query.QueryParser;
import org.onap.aai.parsers.uri.URIToExtensionInformation;
+import org.onap.aai.parsers.uri.URIToObject;
import org.onap.aai.rest.ueb.UEBNotification;
import org.onap.aai.restcore.HttpMethod;
import org.onap.aai.schema.enums.ObjectMetadata;
@@ -93,15 +95,15 @@ public class HttpEntry {
private static final String TARGET_ENTITY = "DB";
private ModelType introspectorFactoryType;
-
+
private QueryStyle queryStyle;
-
+
private SchemaVersion version;
-
+
private Loader loader;
-
+
private TransactionalGraphEngine dbEngine;
-
+
private boolean processSingle = true;
private int paginationBucket = -1;
@@ -148,7 +150,7 @@ public class HttpEntry {
}
- public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType, UEBNotification notification){
+ public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType, UEBNotification notification){
this.version = version;
this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version);
this.dbEngine = new JanusGraphDBEngine(
@@ -161,7 +163,7 @@ public class HttpEntry {
getDbEngine().startTransaction();
return this;
}
-
+
/**
* Gets the introspector factory type.
@@ -316,7 +318,7 @@ public class HttpEntry {
QueryEngine queryEngine = dbEngine.getQueryEngine();
int maxRetries = 10;
int retry = 0;
-
+
LoggingContext.save();
for (DBRequest request : requests) {
response = null;
@@ -358,7 +360,7 @@ public class HttpEntry {
if (requestContextList != null) {
requestContext = requestContextList.get(0);
}
-
+
if (cleanUp == null) {
cleanUp = "false";
}
@@ -426,7 +428,7 @@ public class HttpEntry {
result = formatter.output(vertices.stream().map(vertex -> (Object) vertex).collect(Collectors.toList())).toString();
status = Status.OK;
}
-
+
break;
case PUT:
response = this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
@@ -441,9 +443,9 @@ public class HttpEntry {
}
obj = serializer.getLatestVersionView(v);
if (query.isDependent()) {
- relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
+ relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader);
}
- LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() +
+ LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() +
(long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
LOGGER.info ("Completed ");
LoggingContext.restoreIfPossible();
@@ -454,7 +456,7 @@ public class HttpEntry {
serializer.touchStandardVertexProperties(v, false);
this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
serializer.createEdge(obj, v);
-
+
LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs(),TimeUnit.MILLISECONDS);
LOGGER.info ("Completed");
LoggingContext.restoreIfPossible();
@@ -466,7 +468,7 @@ public class HttpEntry {
existingObj = this.getObjectFromDb(vertices, serializer, query, existingObj, request.getUri(), 0, false, cleanUp);
String existingJson = existingObj.marshal(false);
String newJson;
-
+
if (request.getRawRequestContent().isPresent()) {
newJson = request.getRawRequestContent().get();
} else {
@@ -489,15 +491,15 @@ public class HttpEntry {
status = Status.OK;
patchedObj = serializer.getLatestVersionView(v);
if (query.isDependent()) {
- relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
+ relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, patchedObj, this.loader);
}
- LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() +
+ LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() +
(long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
LOGGER.info ("Completed");
LoggingContext.restoreIfPossible();
notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, patchedObj, relatedObjects, basePath);
} catch (IOException | JsonPatchException e) {
-
+
LOGGER.info ("Caught exception: " + e.getMessage());
LoggingContext.restoreIfPossible();
throw new AAIException("AAI_3000", "could not perform patch operation");
@@ -507,18 +509,18 @@ public class HttpEntry {
String resourceVersion = params.getFirst("resource-version");
obj = serializer.getLatestVersionView(v);
if (query.isDependent()) {
- relatedObjects = this.getRelatedObjects(serializer, queryEngine, v);
+ relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader);
}
/*
* Find all Delete-other-vertex vertices and create structure for notify
- * findDeleatble also returns the startVertex v and we dont want to create
+ * findDeleatble also returns the startVertex v and we dont want to create
* duplicate notification events for the same
* So remove the startvertex first
*/
-
+
List<Vertex> deletableVertices = dbEngine.getQueryEngine().findDeletable(v);
Long vId = (Long) v.id();
-
+
/*
* I am assuming vertexId cant be null
*/
@@ -527,39 +529,39 @@ public class HttpEntry {
Map<Vertex, Introspector> deleteObjects = new HashMap<>();
Map<String, URI> uriMap = new HashMap<>();
Map<String, HashMap<String, Introspector>> deleteRelatedObjects = new HashMap<>();
-
+
if(isDelVerticesPresent){
deleteObjects = this.buildIntrospectorObjects(serializer, deletableVertices);
-
+
uriMap = this.buildURIMap(serializer, deleteObjects);
deleteRelatedObjects = this.buildRelatedObjects(serializer, queryEngine, deleteObjects);
}
-
+
this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true);
serializer.delete(v, deletableVertices, resourceVersion, enableResourceVersion);
this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, false);
-
- LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() +
+
+ LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() +
(long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS);
LOGGER.info ("Completed");
LoggingContext.restoreIfPossible();
status = Status.NO_CONTENT;
notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects, basePath);
-
+
/*
* Notify delete-other-v candidates
*/
-
+
if(isDelVerticesPresent){
this.buildNotificationEvent(sourceOfTruth, status, transactionId, notification, deleteObjects,
uriMap, deleteRelatedObjects, basePath);
}
-
+
break;
case DELETE_EDGE:
serializer.touchStandardVertexProperties(v, false);
serializer.deleteEdge(obj, v);
-
+
LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs(),TimeUnit.MILLISECONDS);
LOGGER.info ("Completed");
LoggingContext.restoreIfPossible();
@@ -569,8 +571,8 @@ public class HttpEntry {
default:
break;
}
-
-
+
+
/* temporarily adding vertex id to the headers
* to be able to use for testing the vertex id endpoint functionality
* since we presently have no other way of generating those id urls
@@ -606,7 +608,7 @@ public class HttpEntry {
break;
} catch (JanusGraphException e) {
this.dbEngine.rollback();
-
+
LOGGER.info ("Caught exception: " + e.getMessage());
LoggingContext.restoreIfPossible();
AAIException ex = new AAIException("AAI_6142", e);
@@ -655,7 +657,7 @@ public class HttpEntry {
return Pair.with(success, responses);
}
-
+
/**
* Gets the media type.
*
@@ -663,15 +665,15 @@ public class HttpEntry {
* @return the media type
*/
private String getMediaType(List <MediaType> mediaTypeList) {
- String mediaType = MediaType.APPLICATION_JSON; // json is the default
+ String mediaType = MediaType.APPLICATION_JSON; // json is the default
for (MediaType mt : mediaTypeList) {
if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) {
mediaType = MediaType.APPLICATION_XML;
- }
+ }
}
return mediaType;
}
-
+
/**
* Gets the object from db.
*
@@ -691,19 +693,19 @@ public class HttpEntry {
* @throws NoSuchMethodException the no such method exception
* @throws UnsupportedEncodingException the unsupported encoding exception
* @throws MalformedURLException the malformed URL exception
- * @throws AAIUnknownObjectException
- * @throws URISyntaxException
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
*/
private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException {
-
- //nothing found
- if (results.isEmpty()) {
- String msg = createNotFoundMessage(query.getResultType(), uri);
+
+ //nothing found
+ if (results.isEmpty()) {
+ String msg = createNotFoundMessage(query.getResultType(), uri);
throw new AAIException("AAI_6114", msg);
- }
+ }
+
+ return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp);
- return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp);
-
}
/**
@@ -800,7 +802,7 @@ public class HttpEntry {
return response;
}
-
+
/**
* Creates the not found message.
*
@@ -809,12 +811,12 @@ public class HttpEntry {
* @return the string
*/
private String createNotFoundMessage(String resultType, URI uri) {
-
- String msg = "No Node of type " + resultType + " found at: " + uri.getPath();
- return msg;
+ String msg = "No Node of type " + resultType + " found at: " + uri.getPath();
+
+ return msg;
}
-
+
/**
* Sets the depth.
*
@@ -831,11 +833,11 @@ public class HttpEntry {
return depth;
}
- if(depthParam == null){
+ if(depthParam == null){
if(this.version.compareTo(schemaVersions.getDepthVersion()) >= 0){
depth = 0;
} else {
- depth = AAIProperties.MAXIMUM_DEPTH;
+ depth = AAIProperties.MAXIMUM_DEPTH;
}
} else {
if (!depthParam.isEmpty() && !"all".equals(depthParam)){
@@ -847,16 +849,16 @@ public class HttpEntry {
}
}
- String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH);
-
+ String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH);
+
int maximumDepth = AAIProperties.MAXIMUM_DEPTH;
if(maxDepth != null){
- try {
- maximumDepth = Integer.parseInt(maxDepth);
- } catch(Exception ex){
- throw new AAIException("AAI_4018");
- }
+ try {
+ maximumDepth = Integer.parseInt(maxDepth);
+ } catch(Exception ex){
+ throw new AAIException("AAI_4018");
+ }
}
if(depth > maximumDepth){
@@ -865,7 +867,7 @@ public class HttpEntry {
return depth;
}
-
+
/**
* Checks if is modification method.
*
@@ -874,31 +876,155 @@ public class HttpEntry {
*/
private boolean isModificationMethod(HttpMethod method) {
boolean result = false;
-
+
if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PUT_EDGE) || method.equals(HttpMethod.DELETE_EDGE) || method.equals(HttpMethod.MERGE_PATCH)) {
result = true;
}
-
+
return result;
-
+
}
-
- private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIException, URISyntaxException {
+
+ /**
+ * Given an uri, introspector object and loader object
+ * it will check if the obj is top level object if it is,
+ * it will return immediately returning the uri passed in
+ * If it isn't, it will go through, get the uriTemplate
+ * from the introspector object and get the count of "/"s
+ * and remove that part of the uri using substring
+ * and keep doing that until the current object is top level
+ * Also added the max depth just so worst case scenario
+ * Then keep adding aai-uri to the list include the aai-uri passed in
+ * Convert that list into an array and return it
+ * <p>
+ *
+ * Example:
+ *
+ * <blockquote>
+ * aai-uri -> /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1
+ *
+ * Given the uriTemplate vserver -> /vservers/vserver/{vserver-id}
+ * it converts to /vservers/vserver
+ *
+ * lastIndexOf /vservers/vserver in /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1
+ * ^
+ * |
+ * |
+ * lastIndexOf
+ * Use substring to get the string from 0 to that lastIndexOf
+ * aai-uri -> /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1
+ *
+ * From this new aai-uri, generate a introspector from the URITOObject class
+ * and keep doing this until you
+ *
+ * </blockquote>
+ *
+ * @param aaiUri - aai-uri of the vertex representating the unique id of a given vertex
+ * @param obj - introspector object of the given starting vertex
+ * @param loader - Type of loader which will always be MoxyLoader to support model driven
+ * @return an array of strings which can be used to get the vertexes of parent and grand parents from a given vertex
+ * @throws UnsupportedEncodingException
+ * @throws AAIException
+ */
+ String[] convertIntrospectorToUriList(String aaiUri, Introspector obj, Loader loader) throws UnsupportedEncodingException, AAIException {
+
+ List<String> uriList = new ArrayList<>();
+ String template = StringUtils.EMPTY;
+ String truncatedUri = aaiUri;
+ int depth = AAIProperties.MAXIMUM_DEPTH;
+ uriList.add(truncatedUri);
+
+ while (depth >= 0 && !obj.isTopLevel()) {
+ template = obj.getMetadata(ObjectMetadata.URI_TEMPLATE);
+
+ if(template == null){
+ LOGGER.warn("Unable to find the uriTemplate for the object {}", obj.getDbName());
+ return null;
+ }
+
+ int templateCount = StringUtils.countMatches(template, "/");
+ int truncatedUriCount = StringUtils.countMatches(truncatedUri, "/");
+
+ if(templateCount > truncatedUriCount){
+ LOGGER.warn("Template uri {} contains more slashes than truncatedUri {}", template, truncatedUri);
+ return null;
+ }
+
+ int cutIndex = StringUtils.ordinalIndexOf(truncatedUri, "/", truncatedUriCount-templateCount+1);
+ truncatedUri = StringUtils.substring(truncatedUri, 0, cutIndex);
+ uriList.add(truncatedUri);
+ obj = new URIToObject(loader, UriBuilder.fromPath(truncatedUri).build()).getEntity();
+ depth--;
+ }
+
+ return uriList.toArray(new String[uriList.size()]);
+ }
+
+ /**
+ *
+ * @param serializer
+ * @param queryEngine
+ * @param v
+ * @param obj
+ * @param loader
+ * @return
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ * @throws InvocationTargetException
+ * @throws SecurityException
+ * @throws InstantiationException
+ * @throws NoSuchMethodException
+ * @throws UnsupportedEncodingException
+ * @throws AAIException
+ * @throws URISyntaxException
+ */
+ private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v, Introspector obj, Loader loader) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIException, URISyntaxException {
+
HashMap<String, Introspector> relatedVertices = new HashMap<>();
- List<Vertex> vertexChain = queryEngine.findParents(v);
- for (Vertex vertex : vertexChain) {
+ VertexProperty aaiUriProperty = v.property(AAIProperties.AAI_URI);
+
+ if(!aaiUriProperty.isPresent()){
+ if(LOGGER.isDebugEnabled()){
+ LOGGER.debug("For the given vertex {}, it seems aai-uri is not present so not getting related objects", v.id().toString());
+ } else {
+ LOGGER.info("It seems aai-uri is not present in vertex, so not getting related objects, for more info enable debug log");
+ }
+ return relatedVertices;
+ }
+
+ String aaiUri = aaiUriProperty.value().toString();
+
+ if(!obj.isTopLevel()){
+ String[] uriList = convertIntrospectorToUriList(aaiUri, obj, loader);
+ List<Vertex> vertexChain = null;
+ // If the uriList is null then there is something wrong with converting the uri
+ // into a list of aai-uris so falling back to the old mechanism for finding parents
+ if(uriList == null){
+ LOGGER.info("Falling back to the old mechanism due to unable to convert aai-uri to list of uris but this is not optimal");
+ vertexChain = queryEngine.findParents(v);
+ } else {
+ vertexChain = queryEngine.findParents(uriList);
+ }
+ for(Vertex vertex : vertexChain){
+ try {
+ final Introspector vertexObj = serializer.getVertexProperties(vertex);
+ relatedVertices.put(vertexObj.getObjectId(), vertexObj);
+ } catch (AAIUnknownObjectException e) {
+ LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
+ }
+ }
+ } else {
try {
- final Introspector vertexObj = serializer.getVertexProperties(vertex);
+ final Introspector vertexObj = serializer.getVertexProperties(v);
relatedVertices.put(vertexObj.getObjectId(), vertexObj);
} catch (AAIUnknownObjectException e) {
LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned");
}
-
}
-
+
return relatedVertices;
}
-
+
private Map<Vertex, Introspector> buildIntrospectorObjects(DBSerializer serializer, Iterable<Vertex> vertices) {
Map<Vertex, Introspector> deleteObjectMap = new HashMap<>();
for (Vertex vertex : vertices) {
@@ -944,7 +1070,7 @@ public class HttpEntry {
for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) {
try {
HashMap<String, Introspector> relatedObjects = this.getRelatedObjects(serializer, queryEngine,
- entry.getKey());
+ entry.getKey(), entry.getValue(), this.loader);
if (null != entry.getValue())
relatedObjectsMap.put(entry.getValue().getObjectId(), relatedObjects);
} catch (IllegalAccessException | IllegalArgumentException
@@ -959,7 +1085,7 @@ public class HttpEntry {
return relatedObjectsMap;
}
-
+
private void buildNotificationEvent(String sourceOfTruth, Status status, String transactionId,
UEBNotification notification, Map<Vertex, Introspector> deleteObjects, Map<String, URI> uriMap,
Map<String, HashMap<String, Introspector>> deleteRelatedObjects, String basePath) {
@@ -980,4 +1106,27 @@ public class HttpEntry {
}
}
}
+
+ public void setPaginationParameters(String resultIndex, String resultSize) {
+ if (resultIndex != null && resultIndex != "-1" && resultSize != null && resultSize != "-1") {
+ this.setPaginationIndex(Integer.parseInt(resultIndex));
+ this.setPaginationBucket(Integer.parseInt(resultSize));
+ }
+ }
+
+ public List<Object> getPaginatedVertexList(List<Object> vertexList) throws AAIException{
+ List<Object> vertices;
+ if(this.isPaginated()) {
+ this.setTotalsForPaging(vertexList.size(), this.getPaginationBucket());
+ int startIndex = (this.getPaginationIndex() - 1) * this.getPaginationBucket();
+ int endIndex = Math.min((this.getPaginationBucket() * this.getPaginationIndex()), vertexList.size());
+ if(startIndex > endIndex){
+ throw new AAIException("AAI_6150"," ResultIndex is not appropriate for the result set, Needs to be <= "+ endIndex);
+ }
+ vertices = vertexList.subList(startIndex, endIndex);
+ }else{
+ vertices = vertexList;
+ }
+ return vertices;
+ }
}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java b/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java
index 7a2c447e..9d107b1f 100644
--- a/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java
+++ b/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java
@@ -23,18 +23,21 @@ package org.onap.aai.serialization.db;
import com.att.eelf.configuration.EELFLogger;
import com.att.eelf.configuration.EELFManager;
import com.google.common.base.CaseFormat;
-import org.janusgraph.core.SchemaViolationException;
+import com.google.common.collect.Multimap;
import org.apache.commons.collections.IteratorUtils;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
import org.apache.tinkerpop.gremlin.structure.*;
-import org.javatuples.Pair;
+import org.janusgraph.core.SchemaViolationException;
import org.javatuples.Triplet;
+import org.onap.aai.concurrent.AaiCallable;
+import org.onap.aai.config.SpringContextAware;
import org.onap.aai.db.props.AAIProperties;
import org.onap.aai.edges.EdgeIngestor;
import org.onap.aai.edges.EdgeRule;
import org.onap.aai.edges.EdgeRuleQuery;
+import org.onap.aai.edges.TypeAlphabetizer;
import org.onap.aai.edges.enums.AAIDirection;
import org.onap.aai.edges.enums.EdgeField;
import org.onap.aai.edges.enums.EdgeProperty;
@@ -57,6 +60,7 @@ import org.onap.aai.schema.enums.PropertyMetadata;
import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException;
import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException;
import org.onap.aai.serialization.engines.TransactionalGraphEngine;
+import org.onap.aai.serialization.engines.query.QueryEngine;
import org.onap.aai.serialization.tinkerpop.TreeBackedVertex;
import org.onap.aai.setup.SchemaVersion;
import org.onap.aai.setup.SchemaVersions;
@@ -64,8 +68,6 @@ import org.onap.aai.util.AAIConfig;
import org.onap.aai.util.AAIConstants;
import org.onap.aai.workarounds.NamingExceptions;
import org.springframework.context.ApplicationContext;
-import org.onap.aai.concurrent.AaiCallable;
-import org.onap.aai.config.SpringContextAware;
import javax.ws.rs.core.UriBuilder;
import java.io.UnsupportedEncodingException;
@@ -78,1790 +80,1956 @@ import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
+import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import org.onap.aai.serialization.engines.query.QueryEngine;
+import java.util.stream.Collectors;
public class DBSerializer {
-
- private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
-
- private final TransactionalGraphEngine engine;
- private final String sourceOfTruth;
- private final ModelType introspectionType;
- private final SchemaVersion version;
- private final Loader latestLoader;
- private EdgeSerializer edgeSer;
- private EdgeIngestor edgeRules;
- private final Loader loader;
- private final String baseURL;
- private double dbTimeMsecs = 0;
- private long currentTimeMillis;
-
- private SchemaVersions schemaVersions;
- /**
- * Instantiates a new DB serializer.
- *
- * @param version the version
- * @param engine the engine
- * @param introspectionType the introspection type
- * @param sourceOfTruth the source of truth
- * @throws AAIException
- */
- public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
- this.engine = engine;
- this.sourceOfTruth = sourceOfTruth;
- this.introspectionType = introspectionType;
- this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
- SchemaVersion LATEST = schemaVersions.getDefaultVersion();
- this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST);
- this.version = version;
- this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version);
- this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
- this.currentTimeMillis = System.currentTimeMillis();
- initBeans();
- }
-
- private void initBeans() {
- //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
- ApplicationContext ctx = SpringContextAware.getApplicationContext();
- EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
- setEdgeIngestor(ei);
- EdgeSerializer es = ctx.getBean(EdgeSerializer.class);
- setEdgeSerializer(es);
- }
-
- private void backupESInit() {
- setEdgeSerializer(new EdgeSerializer(this.edgeRules));
- }
-
- public void setEdgeSerializer(EdgeSerializer edgeSer) {
- this.edgeSer = edgeSer;
- }
-
- public EdgeSerializer getEdgeSeriailizer() {
- return this.edgeSer;
- }
-
- public void setEdgeIngestor(EdgeIngestor ei) {
- this.edgeRules = ei;
- }
-
- public EdgeIngestor getEdgeIngestor(){
- return this.edgeRules;
- }
-
- /**
- * Touch standard vertex properties.
- *
- * @param v the v
- * @param isNewVertex the is new vertex
- */
- public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
- String timeNowInSec = Long.toString(currentTimeMillis);
-
- if (isNewVertex) {
- v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
- v.property(AAIProperties.CREATED_TS, timeNowInSec);
- v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
- }
- v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec);
- v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
- v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
-
- }
-
- private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) {
-
- v.property(AAIProperties.NODE_TYPE, nodeType);
- touchStandardVertexProperties(v, isNewVertex);
-
- }
-
-
-
- /**
- * Creates the new vertex.
- *
- * @param wrappedObject the wrapped object
- * @return the vertex
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- */
- public Vertex createNewVertex(Introspector wrappedObject) {
- Vertex v;
- try {
- StopWatch.conditionalStart();
- v = this.engine.tx().addVertex();
- touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
- }
- finally {
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
- return v;
- }
-
- /**
- * Trim class name.
- *
- * @param className the class name
- * @return the string
- */
- /*
- * Removes the classpath from a class name
- */
- public String trimClassName (String className) {
- String returnValue = "";
-
- if (className.lastIndexOf('.') == -1) {
- return className;
- }
- returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
-
- return returnValue;
- }
-
- /**
- * Serialize to db.
- *
- * @param obj the obj
- * @param v the v
- * @param uriQuery the uri query
- * @param identifier the identifier
- * @throws SecurityException the security exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws InstantiationException the instantiation exception
- * @throws InterruptedException the interrupted exception
- * @throws NoSuchMethodException the no such method exception
- * @throws AAIException the AAI exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIUnknownObjectException
- */
- public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
- StopWatch.conditionalStart();
- try {
- if (uriQuery.isDependent()) {
- //try to find the parent
- List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
- if (!vertices.isEmpty()) {
- Vertex parent = vertices.get(0);
- this.reflectDependentVertex(parent, v, obj, requestContext);
- } else {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
- }
- } else {
- serializeSingleVertex(v, obj, requestContext);
- }
-
- } catch (SchemaViolationException e) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_6117", e);
- }
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
-
- public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
- StopWatch.conditionalStart();
- try {
- boolean isTopLevel = obj.isTopLevel();
- if (isTopLevel) {
- addUriIfNeeded(v, obj.getURI());
- }
-
- processObject(obj, v, requestContext);
- if (!isTopLevel) {
- URI uri = this.getURIForVertex(v);
- URIParser parser = new URIParser(this.loader, uri);
- if (parser.validate()) {
- addUriIfNeeded(v, uri.toString());
- }
- }
- } catch (SchemaViolationException e) {
- throw new AAIException("AAI_6117", e);
- }
- finally {
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
- }
-
- private void addUriIfNeeded(Vertex v, String uri) {
- VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
- if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) {
- v.property(AAIProperties.AAI_URI, uri);
- }
- }
-
- /**
- * Process object.
- *
- * @param <T> the generic type
- * @param obj the obj
- * @param v the v
- * @return the list
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws InstantiationException the instantiation exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws AAIException the AAI exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIUnknownObjectException
- */
- /*
- * Helper method for reflectToDb
- * Handles all the property setting
- */
- private <T> List<Vertex> processObject (Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
- Set<String> properties = new LinkedHashSet<>(obj.getProperties());
- properties.remove(AAIProperties.RESOURCE_VERSION);
- List<Vertex> dependentVertexes = new ArrayList<>();
- List<Vertex> processedVertexes = new ArrayList<>();
- boolean isComplexType = false;
- boolean isListType = false;
- if (!obj.isContainer()) {
- this.touchStandardVertexProperties(obj.getDbName(), v, false);
- }
- this.executePreSideEffects(obj, v);
- for (String property : properties) {
- Object value = null;
- final String propertyType;
- propertyType = obj.getType(property);
- isComplexType = obj.isComplexType(property);
- isListType = obj.isListType(property);
- value = obj.getValue(property);
-
- if (!(isComplexType || isListType)) {
- boolean canModify = this.canModify(obj, property, requestContext);
-
- if (canModify) {
- final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
- String dbProperty = property;
- if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
- dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
- }
- if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
- //data linked properties are ephemeral
- //they are populated dynamically on GETs
- continue;
- }
- if (value != null) {
- if (!value.equals(v.property(dbProperty).orElse(null))) {
- if (propertyType.toLowerCase().contains(".long")) {
- v.property(dbProperty, new Integer(((Long)value).toString()));
- } else {
- v.property(dbProperty, value);
- }
- }
- } else {
- v.property(dbProperty).remove();
- }
- }
- } else if (isListType) {
- List<Object> list = (List<Object>)value;
- if (obj.isComplexGenericType(property)) {
- if (list != null) {
- for (Object o : list) {
- Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
- child.setURIChain(obj.getURI());
- processedVertexes.add(reflectDependentVertex(v, child, requestContext));
- }
- }
- } else {
- //simple list case
- engine.setListProperty(v, property, list);
- }
- } else {
- //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
- if (value != null) { //effectively ignore complex properties not included in the object we're processing
- if (value.getClass().isArray()) {
-
- int length = Array.getLength(value);
- for (int i = 0; i < length; i ++) {
- Object arrayElement = Array.get(value, i);
- Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
- child.setURIChain(obj.getURI());
- processedVertexes.add(reflectDependentVertex(v, child, requestContext));
-
- }
- } else if (!property.equals("relationship-list")) {
- // container case
- Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
- if (introspector.isContainer()) {
- dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
- introspector.setURIChain(obj.getURI());
-
- processedVertexes.addAll(processObject(introspector, v, requestContext));
-
- } else {
- dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
- processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
-
- }
- } else if (property.equals("relationship-list")) {
- handleRelationships(obj, v);
- }
- }
- }
- }
- this.writeThroughDefaults(v, obj);
- /* handle those vertexes not touched */
- for (Vertex toBeRemoved : processedVertexes) {
- dependentVertexes.remove(toBeRemoved);
- }
- this.deleteItemsWithTraversal(dependentVertexes);
-
- this.executePostSideEffects(obj, v);
- return processedVertexes;
- }
-
- /**
- * Handle relationships.
- *
- * @param obj the obj
- * @param vertex the vertex
- * @throws SecurityException the security exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- */
- /*
- * Handles the explicit relationships defined for an obj
- */
- private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
-
-
-
- Introspector wrappedRl = obj.getWrappedValue("relationship-list");
- processRelationshipList(wrappedRl, vertex);
-
-
- }
-
-
- /**
- * Process relationship list.
- *
- * @param wrapped the wrapped
- * @param v the v
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- */
- private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
-
- List<Object> relationships = (List<Object>)wrapped.getValue("relationship");
-
- List<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
- List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
-
- for (Object relationship : relationships) {
- Edge e = null;
- Vertex cousinVertex = null;
- String label = null;
- Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
- QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
-
- if (wrappedRel.hasProperty("relationship-label")) {
- label = wrappedRel.getValue("relationship-label");
- }
-
- List<Vertex> results = parser.getQueryBuilder().toList();
- if (results.isEmpty()) {
- final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
- ex.getTemplateVars().add(parser.getResultType());
- ex.getTemplateVars().add(parser.getUri().toString());
- throw ex;
- } else {
- //still an issue if there's more than one
- cousinVertex = results.get(0);
- }
-
- if (cousinVertex != null) {
- String vType = (String)v.property(AAIProperties.NODE_TYPE).value();
- String cousinType = (String)cousinVertex.property(AAIProperties.NODE_TYPE).value();
- EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label);
-
-
- if (!edgeRules.hasRule(baseQ.build())) {
- throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + v.property(AAIProperties.NODE_TYPE).value().toString() + ", "
- + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString() + (label != null ? (" with label " + label):"") +".");
- } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
- throw new AAIException("AAI_6145");
- }
-
- e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
-
- if (e == null) {
- addEdges.add(new Triplet<>(v, cousinVertex, label));
- } else {
- existingEdges.remove(e);
- }
- }
- }
-
- for (Edge edge : existingEdges) {
- edge.remove();
- }
- for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
- try {
- edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2());
- } catch (NoEdgeRuleFoundException e) {
- throw new AAIException("AAI_6129", e);
- }
- }
-
- }
-
- /**
- * Write through defaults.
- *
- * @param v the v
- * @param obj the obj
- * @throws AAIUnknownObjectException
- */
- private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
- Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
- if (latest != null) {
- Set<String> required = latest.getRequiredProperties();
-
- for (String field : required) {
- String defaultValue = null;
- Object vertexProp = null;
- defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
- if (defaultValue != null) {
- vertexProp = v.<Object>property(field).orElse(null);
- if (vertexProp == null) {
- v.property(field, defaultValue);
- }
- }
- }
- }
-
- }
-
-
- /**
- * Reflect dependent vertex.
- *
- * @param v the v
- * @param dependentObj the dependent obj
- * @return the vertex
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws InstantiationException the instantiation exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws AAIException the AAI exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIUnknownObjectException
- */
- private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
-
- //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
- //List<Vertex> items = p.getQuery().toList();
- QueryBuilder<Vertex> query = this.engine.getQueryBuilder(v);
- query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
- query.createKeyQuery(dependentObj);
-
- List<Vertex> items = query.toList();
-
- Vertex dependentVertex = null;
- if (items.size() == 1) {
- dependentVertex = items.get(0);
- this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
- } else {
- this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI());
- dependentVertex = createNewVertex(dependentObj);
- }
-
- return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
-
- }
-
- /**
- * Reflect dependent vertex.
- *
- * @param parent the parent
- * @param child the child
- * @param obj the obj
- * @return the vertex
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws InstantiationException the instantiation exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws AAIException the AAI exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIUnknownObjectException
- */
- private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
-
- String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
- if (parentUri != null) {
- String uri;
- uri = obj.getURI();
- addUriIfNeeded(child, parentUri + uri);
- }
- processObject(obj, child, requestContext);
-
- Edge e;
- e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
- if (e == null) {
- String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
- if (canBeLinked != null && canBeLinked.equals("true")) {
- Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext));
- boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
- if (isFirst) {
- child.property(AAIProperties.LINKED, true);
- }
- }
- edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
- }
- return child;
-
- }
-
- private SchemaVersion getVerForContext(String requestContext) {
- Pattern pattern = Pattern.compile("v[0-9]+");
- Matcher m = pattern.matcher(requestContext);
- if (!m.find()) {
- return this.version;
- } else {
- return new SchemaVersion(requestContext);
- }
- }
-
- /**
- * Db to object.
- *
- * @param vertices the vertices
- * @param obj the obj
- * @param depth the depth
- * @param cleanUp the clean up
- * @return the introspector
- * @throws AAIException the AAI exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws SecurityException the security exception
- * @throws InstantiationException the instantiation exception
- * @throws NoSuchMethodException the no such method exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws MalformedURLException the malformed URL exception
- * @throws AAIUnknownObjectException
- * @throws URISyntaxException
- */
- public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
- final int internalDepth;
- if (depth == Integer.MAX_VALUE) {
- internalDepth = depth--;
- } else {
- internalDepth = depth;
- }
- StopWatch.conditionalStart();
- if (vertices.size() > 1 && !obj.isContainer()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
- } else if (obj.isContainer()) {
- final List getList;
- String listProperty = null;
- for (String property : obj.getProperties()) {
- if (obj.isListType(property) && obj.isComplexGenericType(property)) {
- listProperty = property;
- break;
- }
- }
- final String propertyName = listProperty;
- getList = (List)obj.getValue(listProperty);
-
- /* This is an experimental multithreading experiment
- * on get alls.
- */
- ExecutorService pool = GetAllPool.getInstance().getPool();
-
- List<Future<Object>> futures = new ArrayList<>();
-
- QueryEngine tgEngine = this.engine.getQueryEngine();
- for (Vertex v : vertices) {
-
- AaiCallable<Object> task = new AaiCallable<Object>() {
- @Override
- public Object process() throws UnsupportedEncodingException, AAIException {
- Set<Vertex> seen = new HashSet<>();
- Introspector childObject;
- try {
- childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
- } catch (AAIUnknownObjectException e) {
- throw e;
- }
- Tree<Element> tree = tgEngine.findSubGraph(v, internalDepth, nodeOnly);
- TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
- try {
- dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp);
- } catch (UnsupportedEncodingException e) {
- throw e;
- } catch (AAIException e) {
- throw e;
- }
- return childObject.getUnderlyingObject();
- //getList.add(childObject.getUnderlyingObject());
- }
- };
- futures.add(pool.submit(task));
- }
-
- for (Future<Object> future : futures) {
- try {
- getList.add(future.get());
- } catch (ExecutionException e) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_4000", e);
- } catch (InterruptedException e) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_4000", e);
- }
- }
- } else if (vertices.size() == 1) {
- Set<Vertex> seen = new HashSet<>();
- Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly);
- TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree);
- dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
- } else {
- //obj = null;
- }
-
- dbTimeMsecs += StopWatch.stopIfStarted();
- return obj;
- }
-
- /**
- * Db to object.
- *
- * @param obj the obj
- * @param v the v
- * @param seen the seen
- * @param depth the depth
- * @param cleanUp the clean up
- * @return the introspector
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws SecurityException the security exception
- * @throws InstantiationException the instantiation exception
- * @throws NoSuchMethodException the no such method exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- * @throws MalformedURLException the malformed URL exception
- * @throws AAIUnknownObjectException
- * @throws URISyntaxException
- */
- private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
-
- if (depth < 0) {
- return null;
- }
- depth--;
- seen.add(v);
-
- boolean modified = false;
- for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
- List<Object> getList = null;
- Vertex[] vertices = null;
-
- if (!(obj.isComplexType(property) || obj.isListType(property))) {
- this.copySimpleProperty(property, obj, v);
- modified = true;
- } else {
- if (obj.isComplexType(property)) {
- /* container case */
-
- if (!property.equals("relationship-list") && depth >= 0) {
- Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
- Object result = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp);
- if (result != null) {
- obj.setValue(property, argumentObject.getUnderlyingObject());
- modified = true;
- }
- } else if (property.equals("relationship-list") && !nodeOnly){
- /* relationships need to be handled correctly */
- Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
- relationshipList = createRelationshipList(v, relationshipList, cleanUp);
- if (relationshipList != null) {
- modified = true;
- obj.setValue(property, relationshipList.getUnderlyingObject());
- modified = true;
- }
-
- }
- } else if (obj.isListType(property)) {
-
- if (property.equals("any")) {
- continue;
- }
- String genericType = obj.getGenericTypeClass(property).getSimpleName();
- if (obj.isComplexGenericType(property) && depth >= 0) {
- final String childDbName = convertFromCamelCase(genericType);
- String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
- EdgeRule rule;
-
- try {
- rule = edgeRules.getRule(new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build());
- } catch (EdgeRuleNotFoundException e) {
- throw new NoEdgeRuleFoundException(e);
- } catch (AmbiguousRuleChoiceException e) {
- throw new MultipleEdgeRuleFoundException(e);
- }
- if (!rule.getContains().equals(AAIDirection.NONE.toString())) {
- //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
- Direction ruleDirection = rule.getDirection();
- Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
- List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
- itr = verticesList.stream().filter(item -> {
- return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
- }).iterator();
- if (itr.hasNext()) {
- getList = (List<Object>)obj.getValue(property);
- }
- int processed = 0;
- int removed = 0;
- while (itr.hasNext()) {
- Vertex childVertex = itr.next();
- if (!seen.contains(childVertex)) {
- Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
-
- Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
- if (result != null) {
- getList.add(argumentObject.getUnderlyingObject());
- }
-
- processed++;
- } else {
- removed++;
- LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
- }
- }
- if (processed == 0) {
- //vertices were all seen, reset the list
- getList = null;
- }
- if (processed > 0) {
- modified = true;
- }
- }
- } else if (obj.isSimpleGenericType(property)) {
- List<Object> temp = this.engine.getListProperty(v, property);
- if (temp != null) {
- getList = (List<Object>)obj.getValue(property);
- getList.addAll(temp);
- modified = true;
- }
-
- }
-
- }
-
- }
- }
-
- //no changes were made to this obj, discard the instance
- if (!modified) {
- return null;
- }
- this.enrichData(obj, v);
- return obj;
-
- }
-
-
- public Introspector getVertexProperties(Vertex v) throws AAIException, UnsupportedEncodingException {
- String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
- if (nodeType == null) {
- throw new AAIException("AAI_6143");
- }
-
- Introspector obj = this.latestLoader.introspectorFromName(nodeType);
- Set<Vertex> seen = new HashSet<>();
- int depth = 0;
- String cleanUp = "false";
- boolean nodeOnly = true;
- StopWatch.conditionalStart();
- this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
- dbTimeMsecs += StopWatch.stopIfStarted();
- return obj;
-
- }
- public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException {
- String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
- if (nodeType == null) {
- throw new AAIException("AAI_6143");
- }
- Introspector obj = this.latestLoader.introspectorFromName(nodeType);
- Set<Vertex> seen = new HashSet<>();
- int depth = AAIProperties.MAXIMUM_DEPTH;
- String cleanUp = "false";
- boolean nodeOnly = false;
- StopWatch.conditionalStart();
- Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
- TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
- this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
- dbTimeMsecs += StopWatch.stopIfStarted();
- return obj;
- }
- /**
- * Copy simple property.
- *
- * @param property the property
- * @param obj the obj
- * @param v the v
- * @throws InstantiationException the instantiation exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- */
- private void copySimpleProperty(String property, Introspector obj, Vertex v) {
-
- final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
- String dbPropertyName = property;
-
- if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
- dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
- }
-
-
-
- final Object temp = v.<Object>property(dbPropertyName).orElse(null);
- if (temp != null) {
- obj.setValue(property, temp);
- }
- }
-
- /**
- * Simple db to object.
- *
- * @param obj the obj
- * @param v the v
- * @throws InstantiationException the instantiation exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- */
- private void simpleDbToObject (Introspector obj, Vertex v) {
- for (String property : obj.getProperties()) {
-
-
- if (!(obj.isComplexType(property) || obj.isListType(property))) {
- this.copySimpleProperty(property, obj, v);
- }
- }
- }
-
- /**
- * Creates the relationship list.
- *
- * @param v the v
- * @param obj the obj
- * @param cleanUp the clean up
- * @return the object
- * @throws InstantiationException the instantiation exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- * @throws MalformedURLException the malformed URL exception
- * @throws URISyntaxException
- */
- private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
-
- List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v);
-
- List<Object> relationshipObjList = obj.getValue("relationship");
-
- for (Vertex cousin : cousins) {
- if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
- List<Edge> edges = this.getEdgesBetween(EdgeType.COUSIN, v, cousin);
- for (Edge e : edges) {
- Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
- Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, e);
- if (result != null) {
- relationshipObjList.add(result);
- }
- }
- } else {
- Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
- Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
- if (result != null) {
- relationshipObjList.add(result);
- }
- }
-
- }
-
- if (relationshipObjList.isEmpty()) {
- return null;
- } else {
- return obj;
- }
- }
-
- /**
- * Process edge relationship.
- *
- * @param relationshipObj the relationship obj
- * @param edge the edge
- * @param cleanUp the clean up
- * @return the object
- * @throws InstantiationException the instantiation exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- * @throws MalformedURLException the malformed URL exception
- * @throws AAIUnknownObjectException
- * @throws URISyntaxException
- */
- private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp, Edge edge) throws UnsupportedEncodingException, AAIUnknownObjectException {
-
-
- //we must look up all parents in this case because we need to compute name-properties
- //we cannot used the cached aaiUri to perform this action currently
- Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp));
- //damaged vertex found, ignore
- if (!tuple.isPresent()) {
- return null;
- }
- List<Introspector> list = tuple.get().getValue1();
- URI uri = this.getURIFromList(list);
-
- URIToRelationshipObject uriParser = null;
- Introspector result = null;
- try {
- uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
- result = uriParser.getResult();
- } catch (AAIException | URISyntaxException e) {
- LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.get().getValue0().id().toString() + ": "
- + e.getMessage() + " " + LogFormatTools.getStackTop(e));
- if ("true".equals(cleanUp)) {
- this.deleteWithTraversal(tuple.get().getValue0());
- }
- return null;
- }
- if (!list.isEmpty()) {
- this.addRelatedToProperty(result, list.get(0));
- }
-
- if (edge != null && result.hasProperty("relationship-label")) {
- result.setValue("relationship-label", edge.label());
- }
-
- return result.getUnderlyingObject();
- }
-
- /**
- * Gets the URI for vertex.
- *
- * @param v the v
- * @return the URI for vertex
- * @throws InstantiationException the instantiation exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIUnknownObjectException
- */
- public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
-
- return getURIForVertex(v, false);
- }
-
- public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
- URI uri = UriBuilder.fromPath("/unknown-uri").build();
-
- String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
-
- if (aaiUri != null && !overwrite) {
- uri = UriBuilder.fromPath(aaiUri).build();
- } else {
- StopWatch.conditionalStart();
- Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(this.loader, v, false);
- dbTimeMsecs += StopWatch.stopIfStarted();
- if (tuple.isPresent()) {
- List<Introspector> list = tuple.get().getValue1();
- uri = this.getURIFromList(list);
- }
-
-
- }
- return uri;
- }
- /**
- * Gets the URI from list.
- *
- * @param list the list
- * @return the URI from list
- * @throws UnsupportedEncodingException the unsupported encoding exception
- */
- private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
- String uri = "";
- StringBuilder sb = new StringBuilder();
- for (Introspector i : list) {
- sb.insert(0, i.getURI());
- }
-
- uri = sb.toString();
- return UriBuilder.fromPath(uri).build();
- }
-
- /**
- * Gets the parents.
- *
- * @param start the start
- * @param removeDamaged the remove damaged
- * @return the parents
- * @throws InstantiationException the instantiation exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws AAIUnknownObjectException
- */
- private Optional<Pair<Vertex, List<Introspector>>> getParents(Loader loader, Vertex start, boolean removeDamaged) {
-
- List<Vertex> results = this.engine.getQueryEngine().findParents(start);
- List<Introspector> objs = new ArrayList<>();
- boolean shortCircuit = false;
- for (Vertex v : results) {
- String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
- Introspector obj = null;
- //vertex on the other end of this edge is bad
- if (nodeType == null) {
- //log something here about what was found and that it was removed
- ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString());
- if (removeDamaged) {
- this.deleteWithTraversal(v);
- }
- shortCircuit = true;
- } else {
- try {
- obj = loader.introspectorFromName(nodeType);
- } catch (AAIUnknownObjectException e) {
- LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion());
- obj = null;
- }
- }
-
- if (obj == null) {
- //can't make a valid path because we don't understand this object
- // don't include it
- } else {
- this.simpleDbToObject(obj, v);
- objs.add(obj);
- }
- }
-
- //stop processing and don't return anything for this bad vertex
- if (shortCircuit) {
- return Optional.empty();
- }
-
- return Optional.of(new Pair<>(results.get(results.size()-1), objs));
- }
-
- /**
- * Adds the r
- * @throws AAIUnknownObjectException
- * @throws IllegalArgumentException elated to property.
- *
- * @param relationship the relationship
- * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
- */
- public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
- String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
- List<Introspector> relatedToProperties = new ArrayList<>();
-
- if (nameProps != null) {
- String[] props = nameProps.split(",");
- for (String prop : props) {
- Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
- relatedTo.setValue("property-key", child.getDbName() + "." + prop);
- relatedTo.setValue("property-value", child.getValue(prop));
- relatedToProperties.add(relatedTo);
- }
- }
-
- if (!relatedToProperties.isEmpty()) {
- List relatedToList = (List)relationship.getValue("related-to-property");
- for (Introspector obj : relatedToProperties) {
- relatedToList.add(obj.getUnderlyingObject());
- }
- }
-
- }
-
- /**
- * Creates the edge.
- *
- * @param relationship the relationship
- * @param inputVertex the input vertex
- * @return true, if successful
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- */
- public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
-
- Vertex relatedVertex = null;
- StopWatch.conditionalStart();
- QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
-
- String label = null;
- if (relationship.hasProperty("relationship-label")) {
- label = relationship.getValue("relationship-label");
- }
-
- List<Vertex> results = parser.getQueryBuilder().toList();
- if (results.isEmpty()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
- e.getTemplateVars().add(parser.getResultType());
- e.getTemplateVars().add(parser.getUri().toString());
- throw e;
- } else {
- //still an issue if there's more than one
- relatedVertex = results.get(0);
- }
-
- if (relatedVertex != null) {
-
- Edge e;
- try {
- e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
- if (e == null) {
- edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
- } else {
- //attempted to link two vertexes already linked
- }
- } finally {
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
- }
-
- dbTimeMsecs += StopWatch.stopIfStarted();
- return true;
- }
-
- /**
- * Gets all the edges between of the type.
- *
- * @param aVertex the out vertex
- * @param bVertex the in vertex
- * @return the edges between
- * @throws AAIException the AAI exception
- * @throws NoEdgeRuleFoundException
- */
- private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
-
- List<Edge> result = new ArrayList<>();
-
- if (bVertex != null) {
- GraphTraversal<Vertex, Edge> findEdgesBetween = null;
- findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
- if (EdgeType.TREE.equals(type)) {
- findEdgesBetween = findEdgesBetween
- .not(
- __.or(
- __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
- __.has(EdgeField.PRIVATE.toString(), true)
- )
- );
- } else {
- findEdgesBetween = findEdgesBetween
- .has(EdgeProperty.CONTAINS.toString(), "NONE")
- .not(
- __.has(EdgeField.PRIVATE.toString(), true)
- );
- }
- findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
- result = findEdgesBetween.toList();
- }
-
- return result;
- }
- /**
- * Gets all the edges between the vertexes with the label and type.
- *
- * @param aVertex the out vertex
- * @param bVertex the in vertex
- * @param label
- * @return the edges between
- * @throws AAIException the AAI exception
- */
- private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
-
- List<Edge> result = new ArrayList<>();
-
- if (bVertex != null) {
- String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value();
- String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value();
- EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build();
- EdgeRule rule;
- try {
- rule = edgeRules.getRule(q);
- } catch (EdgeRuleNotFoundException e) {
- throw new NoEdgeRuleFoundException(e);
- } catch (AmbiguousRuleChoiceException e) {
- throw new MultipleEdgeRuleFoundException(e);
- }
- List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex);
- for (Edge edge : edges) {
- if (edge.label().equals(rule.getLabel())) {
- result.add(edge);
- }
- }
- }
-
- return result;
- }
-
- /**
- * Gets the edge between with the label and edge type.
- *
- * @param aVertex the out vertex
- * @param bVertex the in vertex
- * @param label
- * @return the edge between
- * @throws AAIException the AAI exception
- * @throws NoEdgeRuleFoundException
- */
- public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
-
- StopWatch.conditionalStart();
- if (bVertex != null) {
-
- List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex, label);
-
- if (!edges.isEmpty()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- return edges.get(0);
- }
-
- }
- dbTimeMsecs += StopWatch.stopIfStarted();
- return null;
- }
- public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
- return this.getEdgeBetween(type, aVertex, bVertex, null);
- }
-
-
- /**
- * Delete edge.
- *
- * @param relationship the relationship
- * @param inputVertex the input vertex
- * @return true, if successful
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- */
- public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
-
- Vertex relatedVertex = null;
- StopWatch.conditionalStart();
- QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
-
- List<Vertex> results = parser.getQueryBuilder().toList();
-
- String label = null;
- if (relationship.hasProperty("relationship-label")) {
- label = relationship.getValue("relationship-label");
- }
-
- if (results.isEmpty()) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- return false;
- }
-
- relatedVertex = results.get(0);
- Edge edge;
- try {
- edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
- } catch (NoEdgeRuleFoundException e) {
- dbTimeMsecs += StopWatch.stopIfStarted();
- throw new AAIException("AAI_6129", e);
- }
- if (edge != null) {
- edge.remove();
- dbTimeMsecs += StopWatch.stopIfStarted();
- return true;
- } else {
- dbTimeMsecs += StopWatch.stopIfStarted();
- return false;
- }
-
- }
-
- /**
- * Delete items with traversal.
- *
- * @param vertexes the vertexes
- * @throws IllegalStateException the illegal state exception
- */
- public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
-
- for (Vertex v : vertexes) {
+
+ private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class);
+
+ private final TransactionalGraphEngine engine;
+ private final String sourceOfTruth;
+ private final ModelType introspectionType;
+ private final SchemaVersion version;
+ private final Loader latestLoader;
+ private EdgeSerializer edgeSer;
+ private EdgeIngestor edgeRules;
+ private final Loader loader;
+ private final String baseURL;
+ private double dbTimeMsecs = 0;
+ private long currentTimeMillis;
+
+ private SchemaVersions schemaVersions;
+ private Set<String> namedPropNodes;
+ /**
+ * Instantiates a new DB serializer.
+ *
+ * @param version the version
+ * @param engine the engine
+ * @param introspectionType the introspection type
+ * @param sourceOfTruth the source of truth
+ * @throws AAIException
+ */
+ public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException {
+ this.engine = engine;
+ this.sourceOfTruth = sourceOfTruth;
+ this.introspectionType = introspectionType;
+ this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class);
+ SchemaVersion LATEST = schemaVersions.getDefaultVersion();
+ this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST);
+ this.version = version;
+ this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version);
+ this.namedPropNodes = this.latestLoader.getNamedPropNodes();
+ this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE);
+ this.currentTimeMillis = System.currentTimeMillis();
+ initBeans();
+ }
+
+ private void initBeans() {
+ //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this
+ ApplicationContext ctx = SpringContextAware.getApplicationContext();
+ EdgeIngestor ei = ctx.getBean(EdgeIngestor.class);
+ setEdgeIngestor(ei);
+ EdgeSerializer es = ctx.getBean(EdgeSerializer.class);
+ setEdgeSerializer(es);
+ }
+
+ private void backupESInit() {
+ setEdgeSerializer(new EdgeSerializer(this.edgeRules));
+ }
+
+ public void setEdgeSerializer(EdgeSerializer edgeSer) {
+ this.edgeSer = edgeSer;
+ }
+
+ public EdgeSerializer getEdgeSeriailizer() {
+ return this.edgeSer;
+ }
+
+ public void setEdgeIngestor(EdgeIngestor ei) {
+ this.edgeRules = ei;
+ }
+
+ public EdgeIngestor getEdgeIngestor() {
+ return this.edgeRules;
+ }
+
+ /**
+ * Touch standard vertex properties.
+ *
+ * @param v the v
+ * @param isNewVertex the is new vertex
+ */
+ public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) {
+ String timeNowInSec = Long.toString(currentTimeMillis);
+
+ if (isNewVertex) {
+ v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth);
+ v.property(AAIProperties.CREATED_TS, timeNowInSec);
+ v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString());
+ }
+ v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec);
+ v.property(AAIProperties.LAST_MOD_TS, timeNowInSec);
+ v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth);
+
+ }
+
+ private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) {
+
+ v.property(AAIProperties.NODE_TYPE, nodeType);
+ touchStandardVertexProperties(v, isNewVertex);
+
+ }
+
+
+ /**
+ * Creates the new vertex.
+ *
+ * @param wrappedObject the wrapped object
+ * @return the vertex
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public Vertex createNewVertex(Introspector wrappedObject) {
+ Vertex v;
+ try {
+ StopWatch.conditionalStart();
+ v = this.engine.tx().addVertex();
+ touchStandardVertexProperties(wrappedObject.getDbName(), v, true);
+ } finally {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+ return v;
+ }
+
+ /**
+ * Trim class name.
+ *
+ * @param className the class name
+ * @return the string
+ */
+ /*
+ * Removes the classpath from a class name
+ */
+ public String trimClassName(String className) {
+ String returnValue = "";
+
+ if (className.lastIndexOf('.') == -1) {
+ return className;
+ }
+ returnValue = className.substring(className.lastIndexOf('.') + 1, className.length());
+
+ return returnValue;
+ }
+
+ /**
+ * Serialize to db.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @param uriQuery the uri query
+ * @param identifier the identifier
+ * @throws SecurityException the security exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws InterruptedException the interrupted exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException {
+ StopWatch.conditionalStart();
+ try {
+ if (uriQuery.isDependent()) {
+ //try to find the parent
+ List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList();
+ if (!vertices.isEmpty()) {
+ Vertex parent = vertices.get(0);
+ this.reflectDependentVertex(parent, v, obj, requestContext);
+ } else {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier);
+ }
+ } else {
+ serializeSingleVertex(v, obj, requestContext);
+ }
+
+ } catch (SchemaViolationException e) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_6117", e);
+ }
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+
+ public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException {
+ StopWatch.conditionalStart();
+ try {
+ boolean isTopLevel = obj.isTopLevel();
+ if (isTopLevel) {
+ addUriIfNeeded(v, obj.getURI());
+ }
+
+ processObject(obj, v, requestContext);
+ if (!isTopLevel) {
+ URI uri = this.getURIForVertex(v);
+ URIParser parser = new URIParser(this.loader, uri);
+ if (parser.validate()) {
+ addUriIfNeeded(v, uri.toString());
+ }
+ }
+ } catch (SchemaViolationException e) {
+ throw new AAIException("AAI_6117", e);
+ } finally {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+ }
+
+ private void addUriIfNeeded(Vertex v, String uri) {
+ VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI);
+ if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) {
+ v.property(AAIProperties.AAI_URI, uri);
+ }
+ }
+
+ /**
+ * Process object.
+ *
+ * @param <T> the generic type
+ * @param obj the obj
+ * @param v the v
+ * @return the list
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ /*
+ * Helper method for reflectToDb
+ * Handles all the property setting
+ */
+ private <T> List<Vertex> processObject(Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException {
+ Set<String> properties = new LinkedHashSet<>(obj.getProperties());
+ properties.remove(AAIProperties.RESOURCE_VERSION);
+ List<Vertex> dependentVertexes = new ArrayList<>();
+ List<Vertex> processedVertexes = new ArrayList<>();
+ boolean isComplexType = false;
+ boolean isListType = false;
+ if (!obj.isContainer()) {
+ this.touchStandardVertexProperties(obj.getDbName(), v, false);
+ }
+ this.executePreSideEffects(obj, v);
+ for (String property : properties) {
+ Object value = null;
+ final String propertyType;
+ propertyType = obj.getType(property);
+ isComplexType = obj.isComplexType(property);
+ isListType = obj.isListType(property);
+ value = obj.getValue(property);
+
+ if (!(isComplexType || isListType)) {
+ boolean canModify = this.canModify(obj, property, requestContext);
+
+ if (canModify) {
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
+ String dbProperty = property;
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbProperty = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+ if (metadata.containsKey(PropertyMetadata.DATA_LINK)) {
+ //data linked properties are ephemeral
+ //they are populated dynamically on GETs
+ continue;
+ }
+ if (value != null) {
+ if (!value.equals(v.property(dbProperty).orElse(null))) {
+ if (propertyType.toLowerCase().contains(".long")) {
+ v.property(dbProperty, new Integer(((Long) value).toString()));
+ } else {
+ v.property(dbProperty, value);
+ }
+ }
+ } else {
+ v.property(dbProperty).remove();
+ }
+ }
+ } else if (isListType) {
+ List<Object> list = (List<Object>) value;
+ if (obj.isComplexGenericType(property)) {
+ if (list != null) {
+ for (Object o : list) {
+ Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o);
+ child.setURIChain(obj.getURI());
+ processedVertexes.add(reflectDependentVertex(v, child, requestContext));
+ }
+ }
+ } else {
+ //simple list case
+ engine.setListProperty(v, property, list);
+ }
+ } else {
+ //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method
+ if (value != null) { //effectively ignore complex properties not included in the object we're processing
+ if (value.getClass().isArray()) {
+
+ int length = Array.getLength(value);
+ for (int i = 0; i < length; i++) {
+ Object arrayElement = Array.get(value, i);
+ Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement);
+ child.setURIChain(obj.getURI());
+ processedVertexes.add(reflectDependentVertex(v, child, requestContext));
+
+ }
+ } else if (!property.equals("relationship-list")) {
+ // container case
+ Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value);
+ if (introspector.isContainer()) {
+ dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName()));
+ introspector.setURIChain(obj.getURI());
+
+ processedVertexes.addAll(processObject(introspector, v, requestContext));
+
+ } else {
+ dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName()));
+ processedVertexes.add(reflectDependentVertex(v, introspector, requestContext));
+
+ }
+ } else if (property.equals("relationship-list")) {
+ handleRelationships(obj, v);
+ }
+ }
+ }
+ }
+ this.writeThroughDefaults(v, obj);
+ /* handle those vertexes not touched */
+ for (Vertex toBeRemoved : processedVertexes) {
+ dependentVertexes.remove(toBeRemoved);
+ }
+ this.deleteItemsWithTraversal(dependentVertexes);
+
+ this.executePostSideEffects(obj, v);
+ return processedVertexes;
+ }
+
+ /**
+ * Handle relationships.
+ *
+ * @param obj the obj
+ * @param vertex the vertex
+ * @throws SecurityException the security exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ /*
+ * Handles the explicit relationships defined for an obj
+ */
+ private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException {
+
+
+ Introspector wrappedRl = obj.getWrappedValue("relationship-list");
+ processRelationshipList(wrappedRl, vertex);
+
+
+ }
+
+
+ /**
+ * Process relationship list.
+ *
+ * @param wrapped the wrapped
+ * @param v the v
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException {
+
+ List<Object> relationships = (List<Object>) wrapped.getValue("relationship");
+
+ List<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>();
+ List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader());
+
+ for (Object relationship : relationships) {
+ Edge e = null;
+ Vertex cousinVertex = null;
+ String label = null;
+ Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship);
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel);
+
+ if (wrappedRel.hasProperty("relationship-label")) {
+ label = wrappedRel.getValue("relationship-label");
+ }
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+ if (results.isEmpty()) {
+ final AAIException ex = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
+ ex.getTemplateVars().add(parser.getResultType());
+ ex.getTemplateVars().add(parser.getUri().toString());
+ throw ex;
+ } else {
+ //still an issue if there's more than one
+ cousinVertex = results.get(0);
+ }
+
+ if (cousinVertex != null) {
+ String vType = (String) v.property(AAIProperties.NODE_TYPE).value();
+ String cousinType = (String) cousinVertex.property(AAIProperties.NODE_TYPE).value();
+ EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label);
+
+
+ if (!edgeRules.hasRule(baseQ.build())) {
+ throw new AAIException("AAI_6120", "No EdgeRule found for passed nodeTypes: " + v.property(AAIProperties.NODE_TYPE).value().toString() + ", "
+ + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString() + (label != null ? (" with label " + label) : "") + ".");
+ } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) {
+ throw new AAIException("AAI_6145");
+ }
+
+ e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label);
+
+ if (e == null) {
+ addEdges.add(new Triplet<>(v, cousinVertex, label));
+ } else {
+ existingEdges.remove(e);
+ }
+ }
+ }
+
+ for (Edge edge : existingEdges) {
+ edge.remove();
+ }
+ for (Triplet<Vertex, Vertex, String> triplet : addEdges) {
+ try {
+ edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2());
+ } catch (NoEdgeRuleFoundException e) {
+ throw new AAIException("AAI_6129", e);
+ }
+ }
+
+ }
+
+ /**
+ * Write through defaults.
+ *
+ * @param v the v
+ * @param obj the obj
+ * @throws AAIUnknownObjectException
+ */
+ private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException {
+ Introspector latest = this.latestLoader.introspectorFromName(obj.getName());
+ if (latest != null) {
+ Set<String> required = latest.getRequiredProperties();
+
+ for (String field : required) {
+ String defaultValue = null;
+ Object vertexProp = null;
+ defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE);
+ if (defaultValue != null) {
+ vertexProp = v.<Object>property(field).orElse(null);
+ if (vertexProp == null) {
+ v.property(field, defaultValue);
+ }
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Reflect dependent vertex.
+ *
+ * @param v the v
+ * @param dependentObj the dependent obj
+ * @return the vertex
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ //QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI());
+ //List<Vertex> items = p.getQuery().toList();
+ QueryBuilder<Vertex> query = this.engine.getQueryBuilder(v);
+ query.createEdgeTraversal(EdgeType.TREE, v, dependentObj);
+ query.createKeyQuery(dependentObj);
+
+ List<Vertex> items = query.toList();
+
+ Vertex dependentVertex = null;
+ if (items.size() == 1) {
+ dependentVertex = items.get(0);
+ this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), (String) dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String) dependentObj.getURI());
+ } else {
+ this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String) dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String) dependentObj.getURI());
+ dependentVertex = createNewVertex(dependentObj);
+ }
+
+ return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext);
+
+ }
+
+ /**
+ * Reflect dependent vertex.
+ *
+ * @param parent the parent
+ * @param child the child
+ * @param obj the obj
+ * @return the vertex
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws AAIException the AAI exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException {
+
+ String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null);
+ if (parentUri != null) {
+ String uri;
+ uri = obj.getURI();
+ addUriIfNeeded(child, parentUri + uri);
+ }
+ processObject(obj, child, requestContext);
+
+ Edge e;
+ e = this.getEdgeBetween(EdgeType.TREE, parent, child, null);
+
+ if (e == null) {
+ String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED);
+ if (canBeLinked != null && canBeLinked.equals("true")) {
+ Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext));
+ boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext();
+ if (isFirst) {
+ child.property(AAIProperties.LINKED, true);
+ }
+ }
+ edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child);
+ }
+ return child;
+
+ }
+
+ private SchemaVersion getVerForContext(String requestContext) {
+ Pattern pattern = Pattern.compile("v[0-9]+");
+ Matcher m = pattern.matcher(requestContext);
+ if (!m.find()) {
+ return this.version;
+ } else {
+ return new SchemaVersion(requestContext);
+ }
+ }
+
+ /**
+ * Db to object.
+ *
+ * @param vertices the vertices
+ * @param obj the obj
+ * @param depth the depth
+ * @param cleanUp the clean up
+ * @return the introspector
+ * @throws AAIException the AAI exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, String cleanUp) throws UnsupportedEncodingException, AAIException {
+ final int internalDepth;
+ if (depth == Integer.MAX_VALUE) {
+ internalDepth = depth--;
+ } else {
+ internalDepth = depth;
+ }
+ StopWatch.conditionalStart();
+ if (vertices.size() > 1 && !obj.isContainer()) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_6136", "query object mismatch: this object cannot hold multiple items." + obj.getDbName());
+ } else if (obj.isContainer()) {
+ final List getList;
+ String listProperty = null;
+ for (String property : obj.getProperties()) {
+ if (obj.isListType(property) && obj.isComplexGenericType(property)) {
+ listProperty = property;
+ break;
+ }
+ }
+ final String propertyName = listProperty;
+ getList = (List) obj.getValue(listProperty);
+
+ /* This is an experimental multithreading experiment
+ * on get alls.
+ */
+ ExecutorService pool = GetAllPool.getInstance().getPool();
+
+ List<Future<Object>> futures = new ArrayList<>();
+
+ QueryEngine tgEngine = this.engine.getQueryEngine();
+ for (Vertex v : vertices) {
+
+ AaiCallable<Object> task = new AaiCallable<Object>() {
+ @Override
+ public Object process() throws UnsupportedEncodingException, AAIException {
+ Set<Vertex> seen = new HashSet<>();
+ Introspector childObject;
+ try {
+ childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName);
+ } catch (AAIUnknownObjectException e) {
+ throw e;
+ }
+ try {
+ dbToObject(childObject, v, seen, internalDepth, nodeOnly, cleanUp);
+ } catch (UnsupportedEncodingException e) {
+ throw e;
+ } catch (AAIException e) {
+ throw e;
+ }
+ return childObject.getUnderlyingObject();
+ //getList.add(childObject.getUnderlyingObject());
+ }
+ };
+ futures.add(pool.submit(task));
+ }
+
+ for (Future<Object> future : futures) {
+ try {
+ getList.add(future.get());
+ } catch (ExecutionException e) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_4000", e);
+ } catch (InterruptedException e) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_4000", e);
+ }
+ }
+ } else if (vertices.size() == 1) {
+ Set<Vertex> seen = new HashSet<>();
+ dbToObject(obj, vertices.get(0), seen, depth, nodeOnly, cleanUp);
+ } else {
+ //obj = null;
+ }
+
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return obj;
+ }
+
+ /**
+ * Db to object.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @param seen the seen
+ * @param depth the depth
+ * @param cleanUp the clean up
+ * @return the introspector
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException {
+
+ if (depth < 0) {
+ return null;
+ }
+ depth--;
+ seen.add(v);
+
+ boolean modified = false;
+ for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
+ List<Object> getList = null;
+ Vertex[] vertices = null;
+
+ if (!(obj.isComplexType(property) || obj.isListType(property))) {
+ this.copySimpleProperty(property, obj, v);
+ modified = true;
+ } else {
+ if (obj.isComplexType(property)) {
+ /* container case */
+
+ if (!property.equals("relationship-list") && depth >= 0) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
+ Object result = dbToObject(argumentObject, v, seen, depth + 1, nodeOnly, cleanUp);
+ if (result != null) {
+ obj.setValue(property, argumentObject.getUnderlyingObject());
+ modified = true;
+ }
+ } else if (property.equals("relationship-list") && !nodeOnly) {
+ /* relationships need to be handled correctly */
+ Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
+ relationshipList = createRelationshipList(v, relationshipList, cleanUp);
+ if (relationshipList != null) {
+ modified = true;
+ obj.setValue(property, relationshipList.getUnderlyingObject());
+ modified = true;
+ }
+
+ }
+ } else if (obj.isListType(property)) {
+
+ if (property.equals("any")) {
+ continue;
+ }
+ String genericType = obj.getGenericTypeClass(property).getSimpleName();
+ if (obj.isComplexGenericType(property) && depth >= 0) {
+ final String childDbName = convertFromCamelCase(genericType);
+ String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ EdgeRule rule;
+
+ try {
+ rule = edgeRules.getRule(new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build());
+ } catch (EdgeRuleNotFoundException e) {
+ throw new NoEdgeRuleFoundException(e);
+ } catch (AmbiguousRuleChoiceException e) {
+ throw new MultipleEdgeRuleFoundException(e);
+ }
+ if (!rule.getContains().equals(AAIDirection.NONE.toString())) {
+ //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
+ Direction ruleDirection = rule.getDirection();
+ Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
+ List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr);
+ itr = verticesList.stream().filter(item -> {
+ return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
+ }).iterator();
+ if (itr.hasNext()) {
+ getList = (List<Object>) obj.getValue(property);
+ }
+ int processed = 0;
+ int removed = 0;
+ while (itr.hasNext()) {
+ Vertex childVertex = itr.next();
+ if (!seen.contains(childVertex)) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
+
+ Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp);
+ if (result != null) {
+ getList.add(argumentObject.getUnderlyingObject());
+ }
+
+ processed++;
+ } else {
+ removed++;
+ LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
+ }
+ }
+ if (processed == 0) {
+ //vertices were all seen, reset the list
+ getList = null;
+ }
+ if (processed > 0) {
+ modified = true;
+ }
+ }
+ } else if (obj.isSimpleGenericType(property)) {
+ List<Object> temp = this.engine.getListProperty(v, property);
+ if (temp != null) {
+ getList = (List<Object>) obj.getValue(property);
+ getList.addAll(temp);
+ modified = true;
+ }
+
+ }
+
+ }
+
+ }
+ }
+
+ //no changes were made to this obj, discard the instance
+ if (!modified) {
+ return null;
+ }
+ this.enrichData(obj, v);
+ return obj;
+
+ }
+
+
+ public Introspector getVertexProperties(Vertex v) throws AAIException, UnsupportedEncodingException {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (nodeType == null) {
+ throw new AAIException("AAI_6143");
+ }
+
+ Introspector obj = this.latestLoader.introspectorFromName(nodeType);
+ Set<Vertex> seen = new HashSet<>();
+ int depth = 0;
+ String cleanUp = "false";
+ boolean nodeOnly = true;
+ StopWatch.conditionalStart();
+ this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp);
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return obj;
+
+ }
+
+ public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException {
+ String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (nodeType == null) {
+ throw new AAIException("AAI_6143");
+ }
+ Introspector obj = this.latestLoader.introspectorFromName(nodeType);
+ Set<Vertex> seen = new HashSet<>();
+ int depth = AAIProperties.MAXIMUM_DEPTH;
+ String cleanUp = "false";
+ boolean nodeOnly = false;
+ StopWatch.conditionalStart();
+ Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly);
+ TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree);
+ this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp);
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return obj;
+ }
+
+ /**
+ * Copy simple property.
+ *
+ * @param property the property
+ * @param obj the obj
+ * @param v the v
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ */
+ private void copySimpleProperty(String property, Introspector obj, Vertex v) {
+
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
+ String dbPropertyName = property;
+
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+
+
+ final Object temp = v.<Object>property(dbPropertyName).orElse(null);
+ if (temp != null) {
+ obj.setValue(property, temp);
+ }
+ }
+
+
+ /**
+ * Load the introspector from the hashmap for the given property key
+ *
+ * @param property - vertex property
+ * @param obj - introspector object representing the vertex
+ * @param hashMap - Containing a list of pre-fetched properties for a given vertex
+ */
+ private void copySimplePropertyFromHashMap(String property, Introspector obj, Map<String, Object> hashMap){
+
+ final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property);
+ String dbPropertyName = property;
+
+ if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) {
+ dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS);
+ }
+
+ final Object temp = hashMap.getOrDefault(dbPropertyName, null);
+
+ if (temp != null) {
+ obj.setValue(property, temp);
+ }
+ }
+
+ /**
+ * Simple db to object.
+ *
+ * @param obj the obj
+ * @param v the v
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ */
+ private void simpleDbToObject(Introspector obj, Vertex v) {
+ for(String key : obj.getProperties()){
+ this.copySimpleProperty(key, obj, v);
+ }
+ }
+
+
+ public Map<String, Object> convertVertexToHashMap(Introspector obj, Vertex v){
+
+ long startTime = System.currentTimeMillis();
+
+ Set<String> simpleProperties = obj.getSimpleProperties(PropertyPredicates.isVisible());
+ String[] simplePropsArray = new String[simpleProperties.size()];
+ simplePropsArray = simpleProperties.toArray(simplePropsArray);
+
+ Map<String, Object> simplePropsHashMap = new HashMap<>(simplePropsArray.length * 2);
+
+ v.properties(simplePropsArray).forEachRemaining((vp) -> simplePropsHashMap.put(vp.key(), vp.value()));
+
+ return simplePropsHashMap;
+ }
+
+ /**
+ * Creates the relationship list.
+ *
+ * @param v the v
+ * @param obj the obj
+ * @param cleanUp the clean up
+ * @return the object
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws URISyntaxException
+ */
+ private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException {
+
+ String[] cousinRules = new String[0];
+
+ try {
+ cousinRules = edgeRules.retrieveCachedCousinLabels(obj.getDbName());
+ } catch (ExecutionException e) {
+ LOGGER.warn("Encountered an execution exception while retrieving labels for the node type {} using cached", obj.getDbName(), e);
+ }
+
+ List<Vertex> cousins = null;
+ if(cousinRules != null && cousinRules.length != 0){
+ cousins = this.engine.getQueryEngine().findCousinVertices(v, cousinRules);
+ } else {
+ cousins = this.engine.getQueryEngine().findCousinVertices(v);
+ }
+
+ List<Object> relationshipObjList = obj.getValue("relationship");
+ String aNodeType = v.property("aai-node-type").value().toString();
+
+ TypeAlphabetizer alphabetizer = new TypeAlphabetizer();
+
+ EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class);
+ Set<String> keysWithMultipleLabels = edgeIngestor.getMultipleLabelKeys();
+
+ // For the given vertex, find all the cousins
+ // For each cousin retrieve the node type and then
+ // check if the version is greater than the edge label version
+ // meaning is the current version equal to greater than the version
+ // where we introduced the edge labels into the relationship payload
+ // If it is, then we check if the edge key there are multiple labels
+ // If there are multiple labels, then we need to go to the database
+ // to retrieve the labels between itself and cousin vertex
+ // If there is only single label between the edge a and b, then
+ // we can retrieve what that is without going to the database
+ // from using the edge rules json and get the edge rule out of it
+ EdgeRuleQuery.Builder queryBuilder = new EdgeRuleQuery.Builder(aNodeType);
+ for (Vertex cousin : cousins) {
+ VertexProperty vertexProperty = cousin.property("aai-node-type");
+ String bNodeType = null;
+ if(vertexProperty.isPresent()){
+ bNodeType = cousin.property("aai-node-type").value().toString();
+ } else {
+ // If the vertex is missing the aai-node-type
+ // Then its either a bad vertex or its in the process
+ // of getting deleted so we should ignore these vertexes
+ if(LOGGER.isDebugEnabled()){
+ LOGGER.debug("For the vertex {}, unable to retrieve the aai-node-type", v.id().toString());
+ } else {
+ LOGGER.info("Unable to retrieve the aai-node-type for vertex, for more info enable debug log");
+ }
+ continue;
+ }
+ if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) {
+ String edgeKey = alphabetizer.buildAlphabetizedKey(aNodeType, bNodeType);
+ if(keysWithMultipleLabels.contains(edgeKey)){
+ List<String> edgeLabels = this.getEdgeLabelsBetween(EdgeType.COUSIN, v, cousin);
+ for(String edgeLabel: edgeLabels){
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, edgeLabel);
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+ }
+ } else {
+
+ EdgeRule edgeRule = null;
+
+ // Create a query based on the a nodetype and b nodetype
+ // which is also a cousin edge and ensure the version
+ // is used properly so for example in order to be backwards
+ // compatible if we had allowed a edge between a and b
+ // in a previous release and we decided to remove it from
+ // the edge rules in the future we can display the edge
+ // only for the older apis and the new apis if the edge rule
+ // is removed will not be seen in the newer version of the API
+
+ EdgeRuleQuery ruleQuery = queryBuilder
+ .to(bNodeType)
+ .edgeType(EdgeType.COUSIN)
+ .version(obj.getVersion())
+ .build();
+
+ try {
+ edgeRule = edgeIngestor.getRule(ruleQuery);
+ } catch (EdgeRuleNotFoundException e) {
+ LOGGER.warn("Caught an edge rule not found exception for query {}, {}," +
+ " it could be the edge rule is no longer valid for the existing edge in db",
+ ruleQuery, LogFormatTools.getStackTop(e));
+ continue;
+ } catch (AmbiguousRuleChoiceException e) {
+ LOGGER.error("Caught an ambiguous rule not found exception for query {}, {}",
+ ruleQuery, LogFormatTools.getStackTop(e));
+ continue;
+ }
+
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp,edgeRule.getLabel());
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+ }
+ } else {
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+ }
+
+ }
+
+ if (relationshipObjList.isEmpty()) {
+ return null;
+ } else {
+ return obj;
+ }
+ }
+
+ /**
+ * Process edge relationship.
+ *
+ * @param relationshipObj the relationship obj
+ * @param edge the edge
+ * @param cleanUp the clean up
+ * @return the object
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp, String edgeLabel) throws UnsupportedEncodingException, AAIUnknownObjectException {
+
+ VertexProperty aaiUriProperty = cousin.property("aai-uri");
+
+ if(!aaiUriProperty.isPresent()){
+ return null;
+ }
+
+ URI uri = UriBuilder.fromUri(aaiUriProperty.value().toString()).build();
+
+ URIToRelationshipObject uriParser = null;
+ Introspector result = null;
+ try {
+ uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL);
+ result = uriParser.getResult();
+ } catch (AAIException | URISyntaxException e) {
+ LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + ": "
+ + e.getMessage() + " " + LogFormatTools.getStackTop(e));
+ return null;
+ }
+
+ VertexProperty cousinVertexNodeType = cousin.property(AAIProperties.NODE_TYPE);
+
+ if(cousinVertexNodeType.isPresent()){
+ if(namedPropNodes.contains(cousinVertexNodeType.value().toString())){
+ Introspector cousinObj = loader.introspectorFromName(cousinVertexNodeType.value().toString());
+ this.simpleDbToObject(cousinObj, cousin);
+ this.addRelatedToProperty(result, cousinObj);
+ }
+ }
+
+ if (edgeLabel != null && result.hasProperty("relationship-label")) {
+ result.setValue("relationship-label", edgeLabel);
+ }
+
+ return result.getUnderlyingObject();
+ }
+
+ /**
+ * Gets the URI for vertex.
+ *
+ * @param v the v
+ * @return the URI for vertex
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIUnknownObjectException
+ */
+ public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException {
+
+ return getURIForVertex(v, false);
+ }
+
+ public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException {
+ URI uri = UriBuilder.fromPath("/unknown-uri").build();
+
+ String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null);
+
+ if (aaiUri != null && !overwrite) {
+ uri = UriBuilder.fromPath(aaiUri).build();
+ }
+
+ return uri;
+ }
+
+ /**
+ * Gets the URI from list.
+ *
+ * @param list the list
+ * @return the URI from list
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ */
+ private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException {
+ String uri = "";
+ StringBuilder sb = new StringBuilder();
+ for (Introspector i : list) {
+ sb.insert(0, i.getURI());
+ }
+
+ uri = sb.toString();
+ return UriBuilder.fromPath(uri).build();
+ }
+
+ /**
+ * Adds the r
+ *
+ * @param relationship the relationship
+ * @param child the throws IllegalArgumentException, AAIUnknownObjectException child
+ * @throws AAIUnknownObjectException
+ * @throws IllegalArgumentException elated to property.
+ */
+ public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException {
+ String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS);
+ List<Introspector> relatedToProperties = new ArrayList<>();
+
+ if (nameProps != null) {
+ String[] props = nameProps.split(",");
+ for (String prop : props) {
+ Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property");
+ relatedTo.setValue("property-key", child.getDbName() + "." + prop);
+ relatedTo.setValue("property-value", child.getValue(prop));
+ relatedToProperties.add(relatedTo);
+ }
+ }
+
+ if (!relatedToProperties.isEmpty()) {
+ List relatedToList = (List) relationship.getValue("related-to-property");
+ for (Introspector obj : relatedToProperties) {
+ relatedToList.add(obj.getUnderlyingObject());
+ }
+ }
+
+ }
+
+ /**
+ * Creates the edge.
+ *
+ * @param relationship the relationship
+ * @param inputVertex the input vertex
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
+
+ Vertex relatedVertex = null;
+ StopWatch.conditionalStart();
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ String label = null;
+ if (relationship.hasProperty("relationship-label")) {
+ label = relationship.getValue("relationship-label");
+ }
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+ if (results.isEmpty()) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ AAIException e = new AAIException("AAI_6129", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri());
+ e.getTemplateVars().add(parser.getResultType());
+ e.getTemplateVars().add(parser.getUri().toString());
+ throw e;
+ } else {
+ //still an issue if there's more than one
+ relatedVertex = results.get(0);
+ }
+
+ if (relatedVertex != null) {
+
+ Edge e;
+ try {
+ e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
+ if (e == null) {
+ edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label);
+ } else {
+ //attempted to link two vertexes already linked
+ }
+ } finally {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+ }
+
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return true;
+ }
+
+ /**
+ * Gets all the edges between of the type with the specified label.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private Edge getEdgeBetweenWithLabel(EdgeType type, Vertex aVertex, Vertex bVertex, EdgeRule edgeRule) {
+
+ Edge result = null;
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ if (EdgeType.TREE.equals(type)) {
+ GraphTraversal<Vertex,Vertex> findVertex = this.engine.asAdmin().getTraversalSource().V(bVertex);
+ if(edgeRule.getDirection().equals(Direction.IN)){
+ findEdgesBetween = findVertex.outE(edgeRule.getLabel())
+ .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains())
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ } else {
+ findEdgesBetween = findVertex.inE(edgeRule.getLabel())
+ .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains())
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ }
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(aVertex.id())).limit(1);
+ } else {
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(edgeRule.getLabel());
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id())).limit(1);
+ }
+ List<Edge> list = findEdgesBetween.toList();
+ if(!list.isEmpty()){
+ result = list.get(0);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets all the edges between of the type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
+
+ List<Edge> result = new ArrayList<>();
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
+ if (EdgeType.TREE.equals(type)) {
+ findEdgesBetween = findEdgesBetween
+ .not(
+ __.or(
+ __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
+ __.has(EdgeField.PRIVATE.toString(), true)
+ )
+ );
+ } else {
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ }
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
+ result = findEdgesBetween.toList();
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets all the edges string between of the type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private List<String> getEdgeLabelsBetween(EdgeType type, Vertex aVertex, Vertex bVertex) {
+
+ List<String> result = new ArrayList<>();
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
+ if (EdgeType.TREE.equals(type)) {
+ findEdgesBetween = findEdgesBetween
+ .not(
+ __.or(
+ __.has(EdgeProperty.CONTAINS.toString(), "NONE"),
+ __.has(EdgeField.PRIVATE.toString(), true)
+ )
+ );
+ } else {
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ }
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
+ result = findEdgesBetween.label().toList();
+ }
+ return result;
+ }
+
+ /**
+ * Gets all the edges string between of the type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ private Long getEdgeLabelsCount(Vertex aVertex, Vertex bVertex) {
+
+ Long result = null;
+
+ if (bVertex != null) {
+ GraphTraversal<Vertex, Edge> findEdgesBetween = null;
+ findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE();
+ findEdgesBetween = findEdgesBetween
+ .has(EdgeProperty.CONTAINS.toString(), "NONE")
+ .not(
+ __.has(EdgeField.PRIVATE.toString(), true)
+ );
+ findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id()));
+ result = findEdgesBetween.count().next();
+ }
+ return result;
+ }
+ /**
+ * Gets all the edges between the vertexes with the label and type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @param label
+ * @return the edges between
+ * @throws AAIException the AAI exception
+ */
+ private Edge getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
+
+ Edge edge = null;
+
+ if (bVertex != null) {
+ String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value();
+ String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value();
+ EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build();
+ EdgeRule rule;
+ try {
+ rule = edgeRules.getRule(q);
+ } catch (EdgeRuleNotFoundException e) {
+ throw new NoEdgeRuleFoundException(e);
+ } catch (AmbiguousRuleChoiceException e) {
+ throw new MultipleEdgeRuleFoundException(e);
+ }
+ edge = this.getEdgeBetweenWithLabel(type, aVertex, bVertex, rule);
+ }
+
+ return edge;
+ }
+
+ /**
+ * Gets the edge between with the label and edge type.
+ *
+ * @param aVertex the out vertex
+ * @param bVertex the in vertex
+ * @param label
+ * @return the edge between
+ * @throws AAIException the AAI exception
+ * @throws NoEdgeRuleFoundException
+ */
+ public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException {
+
+ StopWatch.conditionalStart();
+ if (bVertex != null) {
+
+ Edge edge = this.getEdgesBetween(type, aVertex, bVertex, label);
+ if (edge != null) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return edge;
+ }
+
+ }
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return null;
+ }
+
+ public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException {
+ return this.getEdgeBetween(type, aVertex, bVertex, null);
+ }
+
+
+ /**
+ * Delete edge.
+ *
+ * @param relationship the relationship
+ * @param inputVertex the input vertex
+ * @return true, if successful
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ */
+ public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException {
+
+ Vertex relatedVertex = null;
+ StopWatch.conditionalStart();
+ QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship);
+
+ List<Vertex> results = parser.getQueryBuilder().toList();
+
+ String label = null;
+ if (relationship.hasProperty("relationship-label")) {
+ label = relationship.getValue("relationship-label");
+ }
+
+ if (results.isEmpty()) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return false;
+ }
+
+ relatedVertex = results.get(0);
+ Edge edge;
+ try {
+ edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label);
+ } catch (NoEdgeRuleFoundException e) {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ throw new AAIException("AAI_6129", e);
+ }
+ if (edge != null) {
+ edge.remove();
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return true;
+ } else {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ return false;
+ }
+
+ }
+
+ /**
+ * Delete items with traversal.
+ *
+ * @param vertexes the vertexes
+ * @throws IllegalStateException the illegal state exception
+ */
+ public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException {
+
+ for (Vertex v : vertexes) {
LOGGER.debug("About to delete the vertex with id: " + v.id());
- deleteWithTraversal(v);
- }
-
- }
-
- /**
- * Delete with traversal.
- *
- * @param startVertex the start vertex
- */
- public void deleteWithTraversal(Vertex startVertex) {
- StopWatch.conditionalStart();
- List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
-
- for (Vertex v : results) {
- LOGGER.warn("Removing vertex " + v.id().toString());
-
- v.remove();
- }
- dbTimeMsecs += StopWatch.stopIfStarted();
- }
-
- /**
- * Delete.
- *
- * @param v the v
- * @param resourceVersion the resource version
- * @throws IllegalArgumentException the illegal argument exception
- * @throws AAIException the AAI exception
- * @throws InterruptedException the interrupted exception
- */
- public void delete(Vertex v, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
-
- boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
- /*
- * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain
- * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted
- * So its better to make these in 2 steps
- */
- if(result && !deletableVertices.isEmpty()){
- result = verifyPreventDeleteSemantics(deletableVertices);
- }
- if (result) {
-
- try {
- deleteWithTraversal(v);
- } catch (IllegalStateException e) {
- throw new AAIException("AAI_6110", e);
- }
-
- }
-
- }
-
-
- /**
- * Delete.
- *
- * @param v the v
- * @param resourceVersion the resource version
- * @throws IllegalArgumentException the illegal argument exception
- * @throws AAIException the AAI exception
- * @throws InterruptedException the interrupted exception
- */
- public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
-
- boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
-
- if (result) {
-
- try {
- deleteWithTraversal(v);
- } catch (IllegalStateException e) {
- throw new AAIException("AAI_6110", e);
- }
-
- }
-
- }
- /**
- * Verify delete semantics.
- *
- * @param vertex the vertex
- * @param resourceVersion the resource version
- * @return true, if successful
- * @throws AAIException the AAI exception
- */
- private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
- boolean result = true;
- String nodeType = "";
- String errorDetail = " unknown delete semantic found";
- String aaiExceptionCode = "";
- nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
- if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
- }
- List<Vertex> vertices = new ArrayList<Vertex>();
- vertices.add(vertex);
- result = verifyPreventDeleteSemantics(vertices);
-
- return result;
- }
-
- /**
- * Verify Prevent delete semantics.
- * @param vertices the list of vertices
- * @return true, if successful
- * @throws AAIException the AAI exception
- */
- private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException {
- boolean result = true;
- String nodeType = "";
- String errorDetail = " unknown delete semantic found";
- String aaiExceptionCode = "";
-
- StopWatch.conditionalStart();
- /*
- * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition
- * If yes - that should prevent the deletion of the vertex
- * Dedup makes sure we dont capture the prevent-delete vertices twice
- * The prevent-delete vertices are stored so that the error message displays what prevents the delete
- */
-
- List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices).
- union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE),
- __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE))
- .dedup().toList();
-
- dbTimeMsecs += StopWatch.stopIfStarted();
- if (!preventDeleteVertices.isEmpty()) {
- aaiExceptionCode = "AAI_6110";
- errorDetail = String.format("Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types %s", preventDeleteVertices);
- result = false;
- }
- if (!result) {
- throw new AAIException(aaiExceptionCode, errorDetail);
- }
- return result;
- }
-
- /**
- * Verify resource version.
- *
- * @param action the action
- * @param nodeType the node type
- * @param currentResourceVersion the current resource version
- * @param resourceVersion the resource version
- * @param uri the uri
- * @return true, if successful
- * @throws AAIException the AAI exception
- */
- public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
- String enabled = "";
- String errorDetail = "";
- String aaiExceptionCode = "";
- if (currentResourceVersion == null) {
- currentResourceVersion = "";
- }
-
- if (resourceVersion == null) {
- resourceVersion = "";
- }
- try {
- enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
- } catch (AAIException e) {
- ErrorLogHelper.logException(e);
- }
- if (enabled.equals("true")) {
- if (!currentResourceVersion.equals(resourceVersion)) {
- if (action.equals("create") && !resourceVersion.equals("")) {
- errorDetail = "resource-version passed for " + action + " of " + uri;
- aaiExceptionCode = "AAI_6135";
- } else if (resourceVersion.equals("")) {
- errorDetail = "resource-version not passed for " + action + " of " + uri;
- aaiExceptionCode = "AAI_6130";
- } else {
- errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
- aaiExceptionCode = "AAI_6131";
- }
-
- throw new AAIException(aaiExceptionCode, errorDetail);
-
- }
- }
- return true;
- }
-
- /**
- * Convert from camel case.
- *
- * @param name the name
- * @return the string
- */
- private String convertFromCamelCase (String name) {
- String result = "";
- result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
-
- NamingExceptions exceptions = NamingExceptions.getInstance();
- result = exceptions.getDBName(result);
-
- return result;
- }
-
- private boolean canModify(Introspector obj, String propName, String requestContext) {
- final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
- if (readOnly != null) {
- final String[] items = readOnly.split(",");
- for (String item : items) {
- if (requestContext.equals(item)) {
- return false;
- }
- }
- }
- return true;
- }
-
- private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
-
- SideEffectRunner runner = new SideEffectRunner
- .Builder(this.engine, this).addSideEffect(DataCopy.class).addSideEffect(PrivateEdge.class).build();
-
- runner.execute(obj, self);
- }
-
- private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
-
- SideEffectRunner runner = new SideEffectRunner
- .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
-
- runner.execute(obj, self);
- }
-
- private void enrichData(Introspector obj, Vertex self) throws AAIException {
-
- SideEffectRunner runner = new SideEffectRunner
- .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
-
- runner.execute(obj, self);
- }
-
- public double getDBTimeMsecs() {
- return (dbTimeMsecs);
- }
-
- /**
- * Db to object With Filters
- * This is for a one-time run with Tenant Isloation to only filter relationships
- * TODO: Chnage the original dbToObject to take filter parent/cousins
- *
- * @param obj the obj
- * @param v the vertex from the graph
- * @param depth the depth
- * @param nodeOnly specify if to exclude relationships or not
- * @param filterCousinNodes
- * @return the introspector
- * @throws AAIException the AAI exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws SecurityException the security exception
- * @throws InstantiationException the instantiation exception
- * @throws NoSuchMethodException the no such method exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws MalformedURLException the malformed URL exception
- * @throws AAIUnknownObjectException
- * @throws URISyntaxException
- */
- //TODO - See if you can merge the 2 dbToObjectWithFilters
- public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, List<String> filterCousinNodes, List<String> filterParentNodes) throws AAIException, UnsupportedEncodingException {
- String cleanUp = "false";
- if (depth < 0) {
- return null;
- }
- depth--;
- seen.add(v);
- boolean modified = false;
- for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
- List<Object> getList = null;
- Vertex[] vertices = null;
-
- if (!(obj.isComplexType(property) || obj.isListType(property))) {
- this.copySimpleProperty(property, obj, v);
- modified = true;
- } else {
- if (obj.isComplexType(property)) {
- /* container case */
-
- if (!property.equals("relationship-list") && depth >= 0) {
- Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
- Object result = dbToObjectWithFilters(argumentObject, v, seen, depth+1, nodeOnly, filterCousinNodes, filterParentNodes);
- if (result != null) {
- obj.setValue(property, argumentObject.getUnderlyingObject());
- modified = true;
- }
- } else if (property.equals("relationship-list") && !nodeOnly){
- /* relationships need to be handled correctly */
- Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
- relationshipList = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
- if (relationshipList != null) {
- modified = true;
- obj.setValue(property, relationshipList.getUnderlyingObject());
- modified = true;
- }
-
- }
- } else if (obj.isListType(property)) {
-
- if (property.equals("any")) {
- continue;
- }
- String genericType = obj.getGenericTypeClass(property).getSimpleName();
- if (obj.isComplexGenericType(property) && depth >= 0) {
- final String childDbName = convertFromCamelCase(genericType);
- String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
- EdgeRule rule;
-
- boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains);
-
- EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build();
-
- try {
- rule = edgeRules.getRule(q);
- } catch (EdgeRuleNotFoundException e) {
- throw new NoEdgeRuleFoundException(e);
- } catch (AmbiguousRuleChoiceException e) {
- throw new MultipleEdgeRuleFoundException(e);
- }
- if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
- //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
- Direction ruleDirection = rule.getDirection();
- Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
- List<Vertex> verticesList = (List<Vertex>)IteratorUtils.toList(itr);
- itr = verticesList.stream().filter(item -> {
- return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
- }).iterator();
- if (itr.hasNext()) {
- getList = (List<Object>)obj.getValue(property);
- }
- int processed = 0;
- int removed = 0;
- while (itr.hasNext()) {
- Vertex childVertex = itr.next();
- if (!seen.contains(childVertex)) {
- Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
-
- Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes);
- if (result != null) {
- getList.add(argumentObject.getUnderlyingObject());
- }
-
- processed++;
- } else {
- removed++;
- LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
- }
- }
- if (processed == 0) {
- //vertices were all seen, reset the list
- getList = null;
- }
- if (processed > 0) {
- modified = true;
- }
- }
- } else if (obj.isSimpleGenericType(property)) {
- List<Object> temp = this.engine.getListProperty(v, property);
- if (temp != null) {
- getList = (List<Object>)obj.getValue(property);
- getList.addAll(temp);
- modified = true;
- }
-
- }
-
- }
-
- }
- }
-
- //no changes were made to this obj, discard the instance
- if (!modified) {
- return null;
- }
- this.enrichData(obj, v);
- return obj;
-
- }
-
- /**
- * Creates the relationship list with the filtered node types.
- *
- * @param v the v
- * @param obj the obj
- * @param cleanUp the clean up
- * @return the object
- * @throws InstantiationException the instantiation exception
- * @throws IllegalAccessException the illegal access exception
- * @throws IllegalArgumentException the illegal argument exception
- * @throws InvocationTargetException the invocation target exception
- * @throws NoSuchMethodException the no such method exception
- * @throws SecurityException the security exception
- * @throws UnsupportedEncodingException the unsupported encoding exception
- * @throws AAIException the AAI exception
- * @throws MalformedURLException the malformed URL exception
- * @throws URISyntaxException
- */
- private Introspector createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
- List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
-
- Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
- String node = (String)item.property(AAIProperties.NODE_TYPE).orElse("");
- return filterNodes.parallelStream().anyMatch(node::contains);
- }).iterator();
-
-
- List<Vertex> cousins = (List<Vertex>)IteratorUtils.toList(cousinVertices);
-
- //items.parallelStream().anyMatch(inputStr::contains)
- List<Object> relationshipObjList = obj.getValue("relationship");
- for (Vertex cousin : cousins) {
-
- Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
- Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
- if (result != null) {
- relationshipObjList.add(result);
- }
-
-
- }
-
- if (relationshipObjList.isEmpty()) {
- return null;
- } else {
- return obj;
- }
- }
+ deleteWithTraversal(v);
+ }
+
+ }
+
+ /**
+ * Delete with traversal.
+ *
+ * @param startVertex the start vertex
+ */
+ public void deleteWithTraversal(Vertex startVertex) {
+ StopWatch.conditionalStart();
+ List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex);
+
+ for (Vertex v : results) {
+ LOGGER.warn("Removing vertex " + v.id().toString());
+
+ v.remove();
+ }
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+
+ /**
+ * Delete.
+ *
+ * @param v the v
+ * @param resourceVersion the resource version
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws InterruptedException the interrupted exception
+ */
+ public void delete(Vertex v, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
+
+ boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
+ /*
+ * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain
+ * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted
+ * So its better to make these in 2 steps
+ */
+ if (result && !deletableVertices.isEmpty()) {
+ result = verifyPreventDeleteSemantics(deletableVertices);
+ }
+ if (result) {
+
+ try {
+ deleteWithTraversal(v);
+ } catch (IllegalStateException e) {
+ throw new AAIException("AAI_6110", e);
+ }
+
+ }
+
+ }
+
+
+ /**
+ * Delete.
+ *
+ * @param v the v
+ * @param resourceVersion the resource version
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws AAIException the AAI exception
+ * @throws InterruptedException the interrupted exception
+ */
+ public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException {
+
+ boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion);
+
+ if (result) {
+
+ try {
+ deleteWithTraversal(v);
+ } catch (IllegalStateException e) {
+ throw new AAIException("AAI_6110", e);
+ }
+
+ }
+
+ }
+
+ /**
+ * Verify delete semantics.
+ *
+ * @param vertex the vertex
+ * @param resourceVersion the resource version
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException {
+ boolean result = true;
+ String nodeType = "";
+ String errorDetail = " unknown delete semantic found";
+ String aaiExceptionCode = "";
+ nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) {
+ }
+ List<Vertex> vertices = new ArrayList<Vertex>();
+ vertices.add(vertex);
+ result = verifyPreventDeleteSemantics(vertices);
+
+ return result;
+ }
+
+ /**
+ * Verify Prevent delete semantics.
+ *
+ * @param vertices the list of vertices
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException {
+ boolean result = true;
+ String nodeType = "";
+ String errorDetail = " unknown delete semantic found";
+ String aaiExceptionCode = "";
+
+ StopWatch.conditionalStart();
+ /*
+ * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition
+ * If yes - that should prevent the deletion of the vertex
+ * Dedup makes sure we dont capture the prevent-delete vertices twice
+ * The prevent-delete vertices are stored so that the error message displays what prevents the delete
+ */
+
+ List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices).
+ union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE),
+ __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE))
+ .dedup().toList();
+
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ if (!preventDeleteVertices.isEmpty()) {
+ aaiExceptionCode = "AAI_6110";
+ errorDetail = String.format("Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types %s", preventDeleteVertices);
+ result = false;
+ }
+ if (!result) {
+ throw new AAIException(aaiExceptionCode, errorDetail);
+ }
+ return result;
+ }
+
+ /**
+ * Verify resource version.
+ *
+ * @param action the action
+ * @param nodeType the node type
+ * @param currentResourceVersion the current resource version
+ * @param resourceVersion the resource version
+ * @param uri the uri
+ * @return true, if successful
+ * @throws AAIException the AAI exception
+ */
+ public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException {
+ String enabled = "";
+ String errorDetail = "";
+ String aaiExceptionCode = "";
+ if (currentResourceVersion == null) {
+ currentResourceVersion = "";
+ }
+
+ if (resourceVersion == null) {
+ resourceVersion = "";
+ }
+ try {
+ enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG);
+ } catch (AAIException e) {
+ ErrorLogHelper.logException(e);
+ }
+ if (enabled.equals("true")) {
+ if (!currentResourceVersion.equals(resourceVersion)) {
+ if (action.equals("create") && !resourceVersion.equals("")) {
+ errorDetail = "resource-version passed for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6135";
+ } else if (resourceVersion.equals("")) {
+ errorDetail = "resource-version not passed for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6130";
+ } else {
+ errorDetail = "resource-version MISMATCH for " + action + " of " + uri;
+ aaiExceptionCode = "AAI_6131";
+ }
+
+ throw new AAIException(aaiExceptionCode, errorDetail);
+
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Convert from camel case.
+ *
+ * @param name the name
+ * @return the string
+ */
+ private String convertFromCamelCase (String name) {
+ String result = "";
+ result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name);
+
+ NamingExceptions exceptions = NamingExceptions.getInstance();
+ result = exceptions.getDBName(result);
+
+ return result;
+ }
+
+ private boolean canModify(Introspector obj, String propName, String requestContext) {
+ final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY);
+ if (readOnly != null) {
+ final String[] items = readOnly.split(",");
+ for (String item : items) {
+ if (requestContext.equals(item)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataCopy.class).addSideEffect(PrivateEdge.class).build();
+
+ runner.execute(obj, self);
+ }
+
+ private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build();
+
+ runner.execute(obj, self);
+ }
+
+ private void enrichData(Introspector obj, Vertex self) throws AAIException {
+
+ SideEffectRunner runner = new SideEffectRunner
+ .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build();
+
+ runner.execute(obj, self);
+ }
+
+ public double getDBTimeMsecs() {
+ return (dbTimeMsecs);
+ }
+
+ /**
+ * Db to object With Filters
+ * This is for a one-time run with Tenant Isloation to only filter relationships
+ * TODO: Chnage the original dbToObject to take filter parent/cousins
+ *
+ * @param obj the obj
+ * @param v the vertex from the graph
+ * @param depth the depth
+ * @param nodeOnly specify if to exclude relationships or not
+ * @param filterCousinNodes
+ * @return the introspector
+ * @throws AAIException the AAI exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws SecurityException the security exception
+ * @throws InstantiationException the instantiation exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws AAIUnknownObjectException
+ * @throws URISyntaxException
+ */
+ //TODO - See if you can merge the 2 dbToObjectWithFilters
+ public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, List<String> filterCousinNodes, List<String> filterParentNodes) throws AAIException, UnsupportedEncodingException {
+ String cleanUp = "false";
+ if (depth < 0) {
+ return null;
+ }
+ depth--;
+ seen.add(v);
+ boolean modified = false;
+ for (String property : obj.getProperties(PropertyPredicates.isVisible())) {
+ List<Object> getList = null;
+ Vertex[] vertices = null;
+
+ if (!(obj.isComplexType(property) || obj.isListType(property))) {
+ this.copySimpleProperty(property, obj, v);
+ modified = true;
+ } else {
+ if (obj.isComplexType(property)) {
+ /* container case */
+
+ if (!property.equals("relationship-list") && depth >= 0) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property);
+ Object result = dbToObjectWithFilters(argumentObject, v, seen, depth + 1, nodeOnly, filterCousinNodes, filterParentNodes);
+ if (result != null) {
+ obj.setValue(property, argumentObject.getUnderlyingObject());
+ modified = true;
+ }
+ } else if (property.equals("relationship-list") && !nodeOnly) {
+ /* relationships need to be handled correctly */
+ Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property);
+ relationshipList = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes);
+ if (relationshipList != null) {
+ modified = true;
+ obj.setValue(property, relationshipList.getUnderlyingObject());
+ modified = true;
+ }
+
+ }
+ } else if (obj.isListType(property)) {
+
+ if (property.equals("any")) {
+ continue;
+ }
+ String genericType = obj.getGenericTypeClass(property).getSimpleName();
+ if (obj.isComplexGenericType(property) && depth >= 0) {
+ final String childDbName = convertFromCamelCase(genericType);
+ String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null);
+ EdgeRule rule;
+
+ boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains);
+
+ EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build();
+
+ try {
+ rule = edgeRules.getRule(q);
+ } catch (EdgeRuleNotFoundException e) {
+ throw new NoEdgeRuleFoundException(e);
+ } catch (AmbiguousRuleChoiceException e) {
+ throw new MultipleEdgeRuleFoundException(e);
+ }
+ if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) {
+ //vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), childDbName);
+ Direction ruleDirection = rule.getDirection();
+ Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel());
+ List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr);
+ itr = verticesList.stream().filter(item -> {
+ return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName);
+ }).iterator();
+ if (itr.hasNext()) {
+ getList = (List<Object>) obj.getValue(property);
+ }
+ int processed = 0;
+ int removed = 0;
+ while (itr.hasNext()) {
+ Vertex childVertex = itr.next();
+ if (!seen.contains(childVertex)) {
+ Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property);
+
+ Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes);
+ if (result != null) {
+ getList.add(argumentObject.getUnderlyingObject());
+ }
+
+ processed++;
+ } else {
+ removed++;
+ LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString());
+ }
+ }
+ if (processed == 0) {
+ //vertices were all seen, reset the list
+ getList = null;
+ }
+ if (processed > 0) {
+ modified = true;
+ }
+ }
+ } else if (obj.isSimpleGenericType(property)) {
+ List<Object> temp = this.engine.getListProperty(v, property);
+ if (temp != null) {
+ getList = (List<Object>) obj.getValue(property);
+ getList.addAll(temp);
+ modified = true;
+ }
+
+ }
+
+ }
+
+ }
+ }
+
+ //no changes were made to this obj, discard the instance
+ if (!modified) {
+ return null;
+ }
+ this.enrichData(obj, v);
+ return obj;
+
+ }
+
+ /**
+ * Creates the relationship list with the filtered node types.
+ *
+ * @param v the v
+ * @param obj the obj
+ * @param cleanUp the clean up
+ * @return the object
+ * @throws InstantiationException the instantiation exception
+ * @throws IllegalAccessException the illegal access exception
+ * @throws IllegalArgumentException the illegal argument exception
+ * @throws InvocationTargetException the invocation target exception
+ * @throws NoSuchMethodException the no such method exception
+ * @throws SecurityException the security exception
+ * @throws UnsupportedEncodingException the unsupported encoding exception
+ * @throws AAIException the AAI exception
+ * @throws MalformedURLException the malformed URL exception
+ * @throws URISyntaxException
+ */
+ private Introspector createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, List<String> filterNodes) throws UnsupportedEncodingException, AAIException {
+ List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v);
+
+ Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> {
+ String node = (String) item.property(AAIProperties.NODE_TYPE).orElse("");
+ return filterNodes.parallelStream().anyMatch(node::contains);
+ }).iterator();
+
+
+ List<Vertex> cousins = (List<Vertex>) IteratorUtils.toList(cousinVertices);
+
+ //items.parallelStream().anyMatch(inputStr::contains)
+ List<Object> relationshipObjList = obj.getValue("relationship");
+ for (Vertex cousin : cousins) {
+
+ Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship");
+ Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null);
+ if (result != null) {
+ relationshipObjList.add(result);
+ }
+
+
+ }
+
+ if (relationshipObjList.isEmpty()) {
+ return null;
+ } else {
+ return obj;
+ }
+ }
}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java
index 2158c894..d072db55 100644
--- a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java
@@ -30,6 +30,7 @@ import static org.onap.aai.edges.enums.EdgeProperty.DELETE_OTHER_V;
import java.util.List;
import java.util.Set;
+import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
@@ -45,12 +46,12 @@ import org.onap.aai.logging.StopWatch;
/*
* This class needs some big explanation despite its compact size.
- * This controls all the queries performed by the CRUD API in A&AI.
+ * This controls all the queries performed by the CRUD API in A&AI.
* findParents, findChildren, and findDeletable require special attention
* These methods use 'repeat'. You cannot use 'emit' with repeat currently
* as it is extremely buggy as of tinkerpop-3.0.1-incubating. The way around
* it (for now) is to sideEffect all the vertices we traverse into an ArrayList.
- *
+ *
*/
public class GraphTraversalQueryEngine extends QueryEngine {
@@ -70,6 +71,7 @@ public class GraphTraversalQueryEngine extends QueryEngine {
public List<Vertex> findParents(Vertex start) {
try {
StopWatch.conditionalStart();
+
@SuppressWarnings("unchecked")
final GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).emit(v -> true).repeat(__.union(__.inE().has(CONTAINS.toString(), OUT.toString()).outV(), __.outE().has(CONTAINS.toString(), IN.toString()).inV()));
return pipe.toList();
@@ -79,19 +81,36 @@ public class GraphTraversalQueryEngine extends QueryEngine {
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Vertex> findParents(String[] uris) {
+ try {
+ StopWatch.conditionalStart();
+ final GraphTraversal<Vertex, Vertex> pipe = this.g.V()
+ .has(AAIProperties.AAI_URI, P.within(uris))
+ .order().by(AAIProperties.AAI_URI, Order.decr);
+ return pipe.toList();
+ }
+ finally {
+ dbTimeMsecs += StopWatch.stopIfStarted();
+ }
+ }
+
/**
* {@inheritDoc}
*/
@Override
public List<Vertex> findAllChildren(Vertex start) {
-
+
@SuppressWarnings("unchecked")
GraphTraversal<Vertex, Vertex> pipe = this.g
.V(start).emit(v -> true).repeat(__.union(__.outE().has(CONTAINS.toString(), OUT.toString()).inV(), __.inE().has(CONTAINS.toString(), IN.toString()).outV()));
-
+
return pipe.toList();
-
+
}
/**
@@ -104,10 +123,10 @@ public class GraphTraversalQueryEngine extends QueryEngine {
__.outE().has(CONTAINS.toString(), OUT.toString()).inV(),
__.inE().has(CONTAINS.toString(), IN.toString()).outV()
).has(AAIProperties.NODE_TYPE, type).dedup();
-
+
return pipe.toList();
}
-
+
/**
* {@inheritDoc}
*/
@@ -118,7 +137,7 @@ public class GraphTraversalQueryEngine extends QueryEngine {
__.outE().has(CONTAINS.toString(), OUT.toString()),
__.inE().has(CONTAINS.toString(), IN.toString())
).otherV().dedup();
-
+
return pipe.toList();
}
@@ -135,7 +154,7 @@ public class GraphTraversalQueryEngine extends QueryEngine {
__.inE().has(DELETE_OTHER_V.toString(), IN.toString()).outV()
)
).dedup();
-
+
return pipe.toList();
}
@@ -158,11 +177,11 @@ public class GraphTraversalQueryEngine extends QueryEngine {
default:
break;
}
-
+
pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup();
return pipe.toList();
}
-
+
@Override
public Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly) {
final GraphTraversal<Vertex, ?> t = this.g.V(start).emit(v -> true).times(iterations).repeat(
@@ -204,13 +223,13 @@ public class GraphTraversalQueryEngine extends QueryEngine {
__.has("private", true)
)
.dedup();
-
+
return pipeline.toList();
}
@Override
- public List<Vertex> findCousinVertices(Vertex start) {
+ public List<Vertex> findCousinVertices(Vertex start, String... labels) {
// Start at the given vertex
// Do a union to copy the start vertex to be run against all
// so for the start vertex it gets all of in edges that contains other v set to none
@@ -223,8 +242,8 @@ public class GraphTraversalQueryEngine extends QueryEngine {
GraphTraversal<Vertex, Vertex> pipeline = this.g
.V(start)
.union(
- __.inE().has(CONTAINS.toString(), NONE.toString()),
- __.outE().has(CONTAINS.toString(), NONE.toString())
+ __.inE(labels).has(CONTAINS.toString(), NONE.toString()),
+ __.outE(labels).has(CONTAINS.toString(), NONE.toString())
)
.not(
__.has(PRIVATE.toString(), true)
@@ -234,7 +253,7 @@ public class GraphTraversalQueryEngine extends QueryEngine {
return pipeline.toList();
}
-
+
public double getDBTimeMsecs() {
return (dbTimeMsecs);
}
diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java
index c2929468..110f8628 100644
--- a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java
+++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java
@@ -42,16 +42,33 @@ public abstract class QueryEngine {
public QueryEngine (GraphTraversalSource g) {
this.g = g;
}
-
+
/**
* Finds all the parents/grandparents/etc of the given start node.
*
* @param start - the start vertex whose parent chain you want
* @return the list of start and start's parent, grandparent, etc, in
- * order (ie {start, parent, grandparent, etc}
+ * order (ie {start, parent, grandparent, etc}
*/
public abstract List<Vertex> findParents(Vertex start);
-
+
+ /**
+ * Finds all the parents/grandparents/etc of the given start node.
+ *
+ * This method should be used in place of the #findParents(Vertex)
+ * as since the aai-uri is added the lookup for finding the parents
+ * using the given list of aai-uri will be much faster than using
+ * a traversal to follow a start vertex and keep repeating since
+ * as the number of different type of edges keeps growing that call
+ * will be more expensive than using the aai-uri's as they are fast lookup
+ *
+ * @param uris - list of the uris representing the aai-uris of
+ * parent, grandparent, etc
+ * @return the list of start and start's parent, grandparent, etc, in
+ * order (ie {start, parent, grandparent, etc}
+ */
+ public abstract List<Vertex> findParents(String [] uris);
+
/**
* Finds all children, grandchildren, etc of start
*
@@ -59,7 +76,7 @@ public abstract class QueryEngine {
* @return the list of child/grandchild/etc vertices
*/
public abstract List<Vertex> findAllChildren(Vertex start);
-
+
/**
* Finds all immediate children of start (no grandchildren or so forth) of the given type
* @param start - the start vertex
@@ -67,14 +84,14 @@ public abstract class QueryEngine {
* @return the list of immediate child vertices of given type
*/
public abstract List<Vertex> findChildrenOfType(Vertex start, String type);
-
+
/**
* Finds all immediate children of start (no grandchildren or so forth)
* @param start - the start vertex
* @return the list of immediate child vertices
*/
public abstract List<Vertex> findChildren(Vertex start);
-
+
/**
* Find all vertices that should be deleted in a cascade from a delete of start
*
@@ -82,34 +99,34 @@ public abstract class QueryEngine {
* @return the list of vertices to be deleted when start is deleted
*/
public abstract List<Vertex> findDeletable(Vertex start);
-
+
/**
* Finds the subgraph under start, including cousins as well as start's children/grandchildren/etc.
* More specifically, this includes start, all its descendants, start's cousins, and start's
* descendants' cousins (but not any of the cousins' cousins or descendants), and the edges
* connecting them.
- *
+ *
* @param start - the start vertex
- * @return - Tree containing nodes and edges of the subgraph
+ * @return - Tree containing nodes and edges of the subgraph
*/
public Tree<Element> findSubGraph(Vertex start) {
return findSubGraph(start, AAIProperties.MAXIMUM_DEPTH, false);
}
-
+
/**
* Finds the subgraph under start, including cousins as well as start's children/grandchildren/etc.
* More specifically, this includes start, all its descendants, start's cousins, and start's
* descendants' cousins (but not any of the cousins' cousins or descendants), and the edges
* connecting them.
- *
+ *
* @param start - the start vertex
- * @param iterations - depth of the subgraph, this limits how many generations of
+ * @param iterations - depth of the subgraph, this limits how many generations of
* descendants are included
* @param nodeOnly - if true the subgraph will NOT include the cousins
- * @return Tree containing nodes and edges of the subgraph
+ * @return Tree containing nodes and edges of the subgraph
*/
public abstract Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly);
-
+
/**
* Find vertices of type nodeType related to start by edges of the given
* direction and label.
@@ -125,23 +142,23 @@ public abstract class QueryEngine {
/**
* Finds cousin edges connecting start to other vertices only of types defined in an old version.
* The idea is that if a user is using an old version, they won't understand any new node types in
- * subsequent versions. Thus, revealing edges to new types will cause problems. This methods
+ * subsequent versions. Thus, revealing edges to new types will cause problems. This methods
* filters any such edges out.
- *
+ *
* @param start - the start vertex
* @param loader - loader for retrieving the list of allowed node types for the desired version
* (version is set when the loader was instantiated)
* @return list of cousin edges between start and any node types understood by the version specified in loader
*/
public abstract List<Edge> findEdgesForVersion(Vertex start, Loader loader);
-
+
/**
- * Finds all cousins of start.
- *
+ * Finds all cousins of start.
+ *
* @param start - the start vertex
* @return list of start's cousin vertices
*/
- public abstract List<Vertex> findCousinVertices(Vertex start);
+ public abstract List<Vertex> findCousinVertices(Vertex start, String... labels);
public abstract double getDBTimeMsecs();