blob: babe267820427ea00831154d176621b021d1a58f [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.atlas.repository.graph;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.AtlasException;
import org.apache.atlas.RequestContext;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntity.Status;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.instance.AtlasRelationship;
import org.apache.atlas.model.typedef.AtlasRelationshipDef;
import org.apache.atlas.repository.graphdb.AtlasVertexQuery;
import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2;
import org.apache.atlas.type.AtlasArrayType;
import org.apache.atlas.type.AtlasMapType;
import org.apache.atlas.util.AtlasGremlinQueryProvider;
import org.apache.atlas.v1.model.instance.Id;
import org.apache.atlas.v1.model.instance.Referenceable;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
import org.apache.atlas.model.typedef.AtlasRelationshipDef.PropagateTags;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection;
import org.apache.atlas.repository.Constants;
import org.apache.atlas.repository.RepositoryException;
import org.apache.atlas.repository.graphdb.AtlasEdge;
import org.apache.atlas.repository.graphdb.AtlasEdgeDirection;
import org.apache.atlas.repository.graphdb.AtlasElement;
import org.apache.atlas.repository.graphdb.AtlasGraph;
import org.apache.atlas.repository.graphdb.AtlasGraphQuery;
import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasRelationshipType;
import org.apache.atlas.type.AtlasType;
import org.apache.atlas.exception.EntityNotFoundException;
import org.apache.atlas.util.AttributeValueMap;
import org.apache.atlas.util.IndexedInstance;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import static org.apache.atlas.model.instance.AtlasEntity.Status.ACTIVE;
import static org.apache.atlas.model.instance.AtlasEntity.Status.DELETED;
import static org.apache.atlas.repository.Constants.ATTRIBUTE_INDEX_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.ATTRIBUTE_KEY_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_ENTITY_GUID;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_ENTITY_STATUS;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_LABEL;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_EDGE_NAME_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_VERTEX_NAME_KEY;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_VERTEX_PROPAGATE_KEY;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_VERTEX_REMOVE_PROPAGATIONS_KEY;
import static org.apache.atlas.repository.Constants.CREATED_BY_KEY;
import static org.apache.atlas.repository.Constants.ENTITY_TYPE_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.MODIFIED_BY_KEY;
import static org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.RELATIONSHIPTYPE_BLOCKED_PROPAGATED_CLASSIFICATIONS_KEY;
import static org.apache.atlas.repository.Constants.RELATIONSHIPTYPE_TAG_PROPAGATION_KEY;
import static org.apache.atlas.repository.Constants.STATE_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.SUPER_TYPES_PROPERTY_KEY;
import static org.apache.atlas.repository.Constants.TIMESTAMP_PROPERTY_KEY;
import static org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2.isReference;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.BOTH;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.IN;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.OUT;
import static org.apache.atlas.util.AtlasGremlinQueryProvider.AtlasGremlinQuery.TAG_PROPAGATION_IMPACTED_INSTANCES;
import static org.apache.atlas.util.AtlasGremlinQueryProvider.AtlasGremlinQuery.TAG_PROPAGATION_IMPACTED_INSTANCES_EXCLUDE_RELATIONSHIP;
import static org.apache.atlas.util.AtlasGremlinQueryProvider.AtlasGremlinQuery.TAG_PROPAGATION_IMPACTED_INSTANCES_FOR_REMOVAL;
import static org.apache.atlas.util.AtlasGremlinQueryProvider.AtlasGremlinQuery.TAG_PROPAGATION_IMPACTED_INSTANCES_WITH_RESTRICTIONS;
/**
* Utility class for graph operations.
*/
public final class GraphHelper {
private static final Logger LOG = LoggerFactory.getLogger(GraphHelper.class);
public static final String EDGE_LABEL_PREFIX = "__";
public static final String RETRY_COUNT = "atlas.graph.storage.num.retries";
public static final String RETRY_DELAY = "atlas.graph.storage.retry.sleeptime.ms";
public static final String DEFAULT_REMOVE_PROPAGATIONS_ON_ENTITY_DELETE = "atlas.graph.remove.propagations.default";
private final AtlasGremlinQueryProvider queryProvider = AtlasGremlinQueryProvider.INSTANCE;
private static volatile GraphHelper INSTANCE;
private AtlasGraph graph;
private static int maxRetries;
private static long retrySleepTimeMillis;
private static boolean removePropagations;
@VisibleForTesting
GraphHelper(AtlasGraph graph) {
this.graph = graph;
try {
maxRetries = ApplicationProperties.get().getInt(RETRY_COUNT, 3);
retrySleepTimeMillis = ApplicationProperties.get().getLong(RETRY_DELAY, 1000);
removePropagations = ApplicationProperties.get().getBoolean(DEFAULT_REMOVE_PROPAGATIONS_ON_ENTITY_DELETE, false);
} catch (AtlasException e) {
LOG.error("Could not load configuration. Setting to default value for " + RETRY_COUNT, e);
}
}
public static GraphHelper getInstance() {
if ( INSTANCE == null) {
synchronized (GraphHelper.class) {
if (INSTANCE == null) {
INSTANCE = new GraphHelper(AtlasGraphProvider.getGraphInstance());
}
}
}
return INSTANCE;
}
@VisibleForTesting
static GraphHelper getInstance(AtlasGraph graph) {
if ( INSTANCE == null) {
synchronized (GraphHelper.class) {
if (INSTANCE == null) {
INSTANCE = new GraphHelper(graph);
}
}
}
return INSTANCE;
}
public AtlasVertex createVertexWithIdentity(Referenceable typedInstance, Set<String> superTypeNames) {
final String guid = UUID.randomUUID().toString();
final AtlasVertex vertexWithIdentity = createVertexWithoutIdentity(typedInstance.getTypeName(),
new Id(guid, 0, typedInstance.getTypeName()), superTypeNames);
// add identity
AtlasGraphUtilsV2.setEncodedProperty(vertexWithIdentity, Constants.GUID_PROPERTY_KEY, guid);
// add version information
AtlasGraphUtilsV2.setEncodedProperty(vertexWithIdentity, Constants.VERSION_PROPERTY_KEY, Long.valueOf(typedInstance.getId().getVersion()));
return vertexWithIdentity;
}
public AtlasVertex createVertexWithoutIdentity(String typeName, Id typedInstanceId, Set<String> superTypeNames) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating AtlasVertex for type {} id {}", typeName, typedInstanceId != null ? typedInstanceId._getId() : null);
}
final AtlasVertex ret = graph.addVertex();
AtlasGraphUtilsV2.setEncodedProperty(ret, ENTITY_TYPE_PROPERTY_KEY, typeName);
AtlasGraphUtilsV2.setEncodedProperty(ret, STATE_PROPERTY_KEY, ACTIVE.name());
AtlasGraphUtilsV2.setEncodedProperty(ret, TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
AtlasGraphUtilsV2.setEncodedProperty(ret, MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
AtlasGraphUtilsV2.setEncodedProperty(ret, CREATED_BY_KEY, RequestContext.get().getUser());
AtlasGraphUtilsV2.setEncodedProperty(ret, MODIFIED_BY_KEY, RequestContext.get().getUser());
for (String superTypeName : superTypeNames) {
AtlasGraphUtilsV2.addEncodedProperty(ret, SUPER_TYPES_PROPERTY_KEY, superTypeName);
}
return ret;
}
public AtlasEdge addClassificationEdge(AtlasVertex entityVertex, AtlasVertex classificationVertex, boolean isPropagated) {
AtlasEdge ret = addEdge(entityVertex, classificationVertex, CLASSIFICATION_LABEL);
if (ret != null) {
AtlasGraphUtilsV2.setEncodedProperty(ret, CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, getTypeName(classificationVertex));
AtlasGraphUtilsV2.setEncodedProperty(ret, CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, isPropagated);
}
return ret;
}
public AtlasEdge addEdge(AtlasVertex fromVertex, AtlasVertex toVertex, String edgeLabel) {
AtlasEdge ret;
if (LOG.isDebugEnabled()) {
LOG.debug("Adding edge for {} -> label {} -> {}", string(fromVertex), edgeLabel, string(toVertex));
}
ret = graph.addEdge(fromVertex, toVertex, edgeLabel);
if (ret != null) {
AtlasGraphUtilsV2.setEncodedProperty(ret, STATE_PROPERTY_KEY, ACTIVE.name());
AtlasGraphUtilsV2.setEncodedProperty(ret, TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
AtlasGraphUtilsV2.setEncodedProperty(ret, MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
AtlasGraphUtilsV2.setEncodedProperty(ret, CREATED_BY_KEY, RequestContext.get().getUser());
AtlasGraphUtilsV2.setEncodedProperty(ret, MODIFIED_BY_KEY, RequestContext.get().getUser());
if (LOG.isDebugEnabled()) {
LOG.debug("Added {}", string(ret));
}
}
return ret;
}
public AtlasEdge getOrCreateEdge(AtlasVertex outVertex, AtlasVertex inVertex, String edgeLabel) throws RepositoryException {
for (int numRetries = 0; numRetries < maxRetries; numRetries++) {
try {
if (LOG.isDebugEnabled()) {
LOG.debug("Running edge creation attempt {}", numRetries);
}
Iterator<AtlasEdge> edges = getAdjacentEdgesByLabel(inVertex, AtlasEdgeDirection.IN, edgeLabel);
while (edges.hasNext()) {
AtlasEdge edge = edges.next();
if (edge.getOutVertex().equals(outVertex)) {
Id.EntityState edgeState = getState(edge);
if (edgeState == null || edgeState == Id.EntityState.ACTIVE) {
return edge;
}
}
}
return addEdge(outVertex, inVertex, edgeLabel);
} catch (Exception e) {
LOG.warn(String.format("Exception while trying to create edge from %s to %s with label %s. Retrying",
vertexString(outVertex), vertexString(inVertex), edgeLabel), e);
if (numRetries == (maxRetries - 1)) {
LOG.error("Max retries exceeded for edge creation {} {} {} ", outVertex, inVertex, edgeLabel, e);
throw new RepositoryException("Edge creation failed after retries", e);
}
try {
LOG.info("Retrying with delay of {} ms ", retrySleepTimeMillis);
Thread.sleep(retrySleepTimeMillis);
} catch(InterruptedException ie) {
LOG.warn("Retry interrupted during edge creation ");
throw new RepositoryException("Retry interrupted during edge creation", ie);
}
}
}
return null;
}
public AtlasEdge getEdgeByEdgeId(AtlasVertex outVertex, String edgeLabel, String edgeId) {
if (edgeId == null) {
return null;
}
return graph.getEdge(edgeId);
//TODO get edge id is expensive. Use this logic. But doesn't work for now
/**
Iterable<AtlasEdge> edges = outVertex.getEdges(Direction.OUT, edgeLabel);
for (AtlasEdge edge : edges) {
if (edge.getObjectId().toString().equals(edgeId)) {
return edge;
}
}
return null;
**/
}
/**
* Args of the format prop1, key1, prop2, key2...
* Searches for a AtlasVertex with prop1=key1 && prop2=key2
* @param args
* @return AtlasVertex with the given property keys
* @throws AtlasBaseException
*/
public AtlasVertex findVertex(Object... args) throws EntityNotFoundException {
return (AtlasVertex) findElement(true, args);
}
/**
* Args of the format prop1, key1, prop2, key2...
* Searches for a AtlasEdge with prop1=key1 && prop2=key2
* @param args
* @return AtlasEdge with the given property keys
* @throws AtlasBaseException
*/
public AtlasEdge findEdge(Object... args) throws EntityNotFoundException {
return (AtlasEdge) findElement(false, args);
}
private AtlasElement findElement(boolean isVertexSearch, Object... args) throws EntityNotFoundException {
AtlasGraphQuery query = graph.query();
for (int i = 0; i < args.length; i += 2) {
query = query.has((String) args[i], args[i + 1]);
}
Iterator<AtlasElement> results = isVertexSearch ? query.vertices().iterator() : query.edges().iterator();
AtlasElement element = (results != null && results.hasNext()) ? results.next() : null;
if (element == null) {
throw new EntityNotFoundException("Could not find " + (isVertexSearch ? "vertex" : "edge") + " with condition: " + getConditionString(args));
}
if (LOG.isDebugEnabled()) {
LOG.debug("Found {} with condition {}", string(element), getConditionString(args));
}
return element;
}
//In some cases of parallel APIs, the edge is added, but get edge by label doesn't return the edge. ATLAS-1104
//So traversing all the edges
public static Iterator<AtlasEdge> getAdjacentEdgesByLabel(AtlasVertex instanceVertex, AtlasEdgeDirection direction, final String edgeLabel) {
if (LOG.isDebugEnabled()) {
LOG.debug("Finding edges for {} with label {}", string(instanceVertex), edgeLabel);
}
if(instanceVertex != null && edgeLabel != null) {
final Iterator<AtlasEdge> iterator = instanceVertex.getEdges(direction).iterator();
return new Iterator<AtlasEdge>() {
private AtlasEdge edge = null;
@Override
public boolean hasNext() {
while (edge == null && iterator.hasNext()) {
AtlasEdge localEdge = iterator.next();
if (localEdge.getLabel().equals(edgeLabel)) {
edge = localEdge;
}
}
return edge != null;
}
@Override
public AtlasEdge next() {
if (hasNext()) {
AtlasEdge localEdge = edge;
edge = null;
return localEdge;
}
return null;
}
@Override
public void remove() {
throw new IllegalStateException("Not handled");
}
};
}
return null;
}
public static boolean isPropagationEnabled(AtlasVertex classificationVertex) {
boolean ret = false;
if (classificationVertex != null) {
Boolean enabled = AtlasGraphUtilsV2.getEncodedProperty(classificationVertex, CLASSIFICATION_VERTEX_PROPAGATE_KEY, Boolean.class);
ret = (enabled == null) ? true : enabled;
}
return ret;
}
public static boolean getRemovePropagations(AtlasVertex classificationVertex) {
boolean ret = false;
if (classificationVertex != null) {
Boolean enabled = AtlasGraphUtilsV2.getEncodedProperty(classificationVertex, CLASSIFICATION_VERTEX_REMOVE_PROPAGATIONS_KEY, Boolean.class);
ret = (enabled == null) ? true : enabled;
}
return ret;
}
public static AtlasVertex getClassificationVertex(AtlasVertex entityVertex, String classificationName) {
AtlasVertex ret = null;
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL)
.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, false)
.has(CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, classificationName).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
if (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
ret = (edge != null) ? edge.getInVertex() : null;
}
}
return ret;
}
public static AtlasEdge getClassificationEdge(AtlasVertex entityVertex, AtlasVertex classificationVertex) {
AtlasEdge ret = null;
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL)
.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, false)
.has(CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, getTypeName(classificationVertex)).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
if (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
ret = (edge != null && edge.getInVertex().equals(classificationVertex)) ? edge : null;
}
}
return ret;
}
public static AtlasEdge getPropagatedClassificationEdge(AtlasVertex entityVertex, String classificationName, String associatedEntityGuid) {
AtlasEdge ret = null;
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL)
.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, true)
.has(CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, classificationName).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
AtlasVertex classificationVertex = (edge != null) ? edge.getInVertex() : null;
if (classificationVertex != null) {
String guid = AtlasGraphUtilsV2.getEncodedProperty(classificationVertex, CLASSIFICATION_ENTITY_GUID, String.class);
if (StringUtils.equals(guid, associatedEntityGuid)) {
ret = edge;
break;
}
}
}
}
return ret;
}
public static AtlasEdge getPropagatedClassificationEdge(AtlasVertex entityVertex, AtlasVertex classificationVertex) {
AtlasEdge ret = null;
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL)
.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, true)
.has(CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, getTypeName(classificationVertex)).edges();
if (edges != null && classificationVertex != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator != null && iterator.hasNext()) {
AtlasEdge edge = iterator.next();
if (edge != null && edge.getInVertex().equals(classificationVertex)) {
ret = edge;
break;
}
}
}
return ret;
}
public static List<AtlasEdge> getPropagatedEdges(AtlasVertex classificationVertex) {
List<AtlasEdge> ret = new ArrayList<>();
Iterable edges = classificationVertex.query().direction(AtlasEdgeDirection.IN).label(CLASSIFICATION_LABEL)
.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, true)
.has(CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, getTypeName(classificationVertex)).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
ret.add(edge);
}
}
return ret;
}
public static List<AtlasEdge> getIncomingClassificationEdges(AtlasVertex classificationVertex) {
List<AtlasEdge> ret = new ArrayList<>();
String classificationName = getTypeName(classificationVertex);
Iterable edges = classificationVertex.query().direction(AtlasEdgeDirection.IN).label(CLASSIFICATION_LABEL)
.has(CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, classificationName).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
ret.add(edge);
}
}
return ret;
}
public static List<AtlasVertex> getAllPropagatedEntityVertices(AtlasVertex classificationVertex) {
List<AtlasVertex> ret = new ArrayList<>();
if (classificationVertex != null) {
List<AtlasEdge> edges = getPropagatedEdges(classificationVertex);
if (CollectionUtils.isNotEmpty(edges)) {
for (AtlasEdge edge : edges) {
ret.add(edge.getOutVertex());
}
}
}
return ret;
}
public static Iterator<AtlasEdge> getIncomingEdgesByLabel(AtlasVertex instanceVertex, String edgeLabel) {
return getAdjacentEdgesByLabel(instanceVertex, AtlasEdgeDirection.IN, edgeLabel);
}
public static Iterator<AtlasEdge> getOutGoingEdgesByLabel(AtlasVertex instanceVertex, String edgeLabel) {
return getAdjacentEdgesByLabel(instanceVertex, AtlasEdgeDirection.OUT, edgeLabel);
}
public AtlasEdge getEdgeForLabel(AtlasVertex vertex, String edgeLabel, AtlasRelationshipEdgeDirection edgeDirection) {
AtlasEdge ret;
switch (edgeDirection) {
case IN:
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.IN);
break;
case OUT:
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.OUT);
break;
case BOTH:
default:
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.BOTH);
break;
}
return ret;
}
public static Iterator<AtlasEdge> getEdgesForLabel(AtlasVertex vertex, String edgeLabel, AtlasRelationshipEdgeDirection edgeDirection) {
Iterator<AtlasEdge> ret = null;
switch (edgeDirection) {
case IN:
ret = getIncomingEdgesByLabel(vertex, edgeLabel);
break;
case OUT:
ret = getOutGoingEdgesByLabel(vertex, edgeLabel);
break;
case BOTH:
ret = getAdjacentEdgesByLabel(vertex, AtlasEdgeDirection.BOTH, edgeLabel);
break;
}
return ret;
}
/**
* Returns the active edge for the given edge label.
* If the vertex is deleted and there is no active edge, it returns the latest deleted edge
* @param vertex
* @param edgeLabel
* @return
*/
public AtlasEdge getEdgeForLabel(AtlasVertex vertex, String edgeLabel) {
return getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.OUT);
}
public AtlasEdge getEdgeForLabel(AtlasVertex vertex, String edgeLabel, AtlasEdgeDirection edgeDirection) {
Iterator<AtlasEdge> iterator = getAdjacentEdgesByLabel(vertex, edgeDirection, edgeLabel);
AtlasEdge latestDeletedEdge = null;
long latestDeletedEdgeTime = Long.MIN_VALUE;
while (iterator != null && iterator.hasNext()) {
AtlasEdge edge = iterator.next();
Id.EntityState edgeState = getState(edge);
if (edgeState == null || edgeState == Id.EntityState.ACTIVE) {
if (LOG.isDebugEnabled()) {
LOG.debug("Found {}", string(edge));
}
return edge;
} else {
Long modificationTime = edge.getProperty(MODIFICATION_TIMESTAMP_PROPERTY_KEY, Long.class);
if (modificationTime != null && modificationTime >= latestDeletedEdgeTime) {
latestDeletedEdgeTime = modificationTime;
latestDeletedEdge = edge;
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Found {}", latestDeletedEdge == null ? "null" : string(latestDeletedEdge));
}
//If the vertex is deleted, return latest deleted edge
return latestDeletedEdge;
}
public static String vertexString(final AtlasVertex vertex) {
StringBuilder properties = new StringBuilder();
for (String propertyKey : vertex.getPropertyKeys()) {
Collection<?> propertyValues = vertex.getPropertyValues(propertyKey, Object.class);
properties.append(propertyKey).append("=").append(propertyValues.toString()).append(", ");
}
return "v[" + vertex.getIdForDisplay() + "], Properties[" + properties + "]";
}
public static String edgeString(final AtlasEdge edge) {
return "e[" + edge.getLabel() + "], [" + edge.getOutVertex() + " -> " + edge.getLabel() + " -> "
+ edge.getInVertex() + "]";
}
public static <T extends AtlasElement> void setProperty(T element, String propertyName, Object value) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
String elementStr = null;
if (LOG.isDebugEnabled()) {
elementStr = string(element);
LOG.debug("Setting property {} = \"{}\" to {}", actualPropertyName, value, elementStr);
}
Object existValue = element.getProperty(actualPropertyName, Object.class);
if(value == null || (value instanceof Collection && ((Collection) value).isEmpty())) {
if(existValue != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Removing property - {} value from {}", actualPropertyName, elementStr);
}
element.removeProperty(actualPropertyName);
}
} else {
if (!value.equals(existValue)) {
element.setProperty(actualPropertyName, value);
if (LOG.isDebugEnabled()) {
LOG.debug("Set property {} = \"{}\" to {}", actualPropertyName, value, elementStr);
}
}
}
}
/**
* Gets the value of a property that is stored in the graph as a single property value. If
* a multi-property such as {@link Constants#TRAIT_NAMES_PROPERTY_KEY} or {@link Constants#SUPER_TYPES_PROPERTY_KEY}
* is used, an exception will be thrown.
*
* @param element
* @param propertyName
* @param clazz
* @return
*/
public static <T> T getSingleValuedProperty(AtlasElement element, String propertyName, Class<T> clazz) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if (LOG.isTraceEnabled()) {
LOG.trace("Reading property {} from {}", actualPropertyName, string(element));
}
return element.getProperty(actualPropertyName, clazz);
}
public static Object getProperty(AtlasVertex<?,?> vertex, String propertyName) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if (LOG.isTraceEnabled()) {
LOG.trace("Reading property {} from {}", actualPropertyName, string(vertex));
}
if(AtlasGraphProvider.getGraphInstance().isMultiProperty(actualPropertyName)) {
return vertex.getPropertyValues(actualPropertyName, String.class);
}
else {
return vertex.getProperty(actualPropertyName, Object.class);
}
}
public static Object getProperty(AtlasEdge<?,?> edge, String propertyName) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if (LOG.isTraceEnabled()) {
LOG.trace("Reading property {} from {}", actualPropertyName, string(edge));
}
return edge.getProperty(actualPropertyName, Object.class);
}
private static <T extends AtlasElement> String string(T element) {
if (element instanceof AtlasVertex) {
return string((AtlasVertex) element);
} else if (element instanceof AtlasEdge) {
return string((AtlasEdge)element);
}
return element.toString();
}
/**
* Adds an additional value to a multi-property (SET).
*
* @param vertex
* @param propertyName
* @param value
*/
public static void addProperty(AtlasVertex vertex, String propertyName, Object value) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
if (LOG.isDebugEnabled()) {
LOG.debug("Adding property {} = \"{}\" to vertex {}", actualPropertyName, value, string(vertex));
}
vertex.addProperty(actualPropertyName, value);
}
public static void addToPropagatedTraitNames(AtlasVertex entityVertex, String classificationName) {
if (LOG.isDebugEnabled()) {
LOG.debug("Adding property {} = \"{}\" to vertex {}", PROPAGATED_TRAIT_NAMES_PROPERTY_KEY, classificationName, string(entityVertex));
}
entityVertex.addListProperty(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY, classificationName);
}
public static void removeFromPropagatedTraitNames(AtlasVertex entityVertex, String classificationName) {
if (entityVertex != null && StringUtils.isNotEmpty(classificationName)) {
List<String> propagatedTraitNames = getTraitNames(entityVertex, true);
propagatedTraitNames.remove(classificationName);
entityVertex.removeProperty(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY);
for (String propagatedTraitName : propagatedTraitNames) {
addToPropagatedTraitNames(entityVertex, propagatedTraitName);
}
}
}
/**
* Remove the specified edge from the graph.
*
* @param edge
*/
public void removeEdge(AtlasEdge edge) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> removeEdge({})", string(edge));
}
graph.removeEdge(edge);
if (LOG.isDebugEnabled()) {
LOG.info("<== removeEdge()");
}
}
/**
* Remove the specified AtlasVertex from the graph.
*
* @param vertex
*/
public void removeVertex(AtlasVertex vertex) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> GraphHelper.removeVertex({})", string(vertex));
}
graph.removeVertex(vertex);
if (LOG.isDebugEnabled()) {
LOG.debug("<== GraphHelper.removeVertex()");
}
}
public AtlasVertex getVertexForGUID(String guid) throws EntityNotFoundException {
return findVertex(Constants.GUID_PROPERTY_KEY, guid);
}
public AtlasEdge getEdgeForGUID(String guid) throws AtlasBaseException {
AtlasEdge ret;
try {
ret = findEdge(Constants.RELATIONSHIP_GUID_PROPERTY_KEY, guid);
} catch (EntityNotFoundException e) {
throw new AtlasBaseException(AtlasErrorCode.RELATIONSHIP_GUID_NOT_FOUND, guid);
}
return ret;
}
/**
* Finds the Vertices that correspond to the given property values. Property
* values that are not found in the graph will not be in the map.
*
* @return propertyValue to AtlasVertex map with the result.
*/
public Map<String, AtlasVertex> getVerticesForPropertyValues(String property, List<String> values) {
if(values.isEmpty()) {
return Collections.emptyMap();
}
Collection<String> nonNullValues = new HashSet<>(values.size());
for(String value : values) {
if(value != null) {
nonNullValues.add(value);
}
}
//create graph query that finds vertices with the guids
AtlasGraphQuery query = graph.query();
query.in(property, nonNullValues);
Iterable<AtlasVertex> results = query.vertices();
Map<String, AtlasVertex> result = new HashMap<>(values.size());
//Process the result, using the guidToIndexMap to figure out where
//each vertex should go in the result list.
for(AtlasVertex vertex : results) {
if(vertex.exists()) {
String propertyValue = vertex.getProperty(property, String.class);
if(LOG.isDebugEnabled()) {
LOG.debug("Found a vertex {} with {} = {}", string(vertex), property, propertyValue);
}
result.put(propertyValue, vertex);
}
}
return result;
}
public List<AtlasVertex> getIncludedImpactedVerticesWithReferences(AtlasVertex entityVertex, String relationshipGuid) throws AtlasBaseException {
List<AtlasVertex> ret = new ArrayList<>();
List<AtlasVertex> impactedVertices = getImpactedVerticesWithReferences(getGuid(entityVertex), relationshipGuid);
ret.add(entityVertex);
if (CollectionUtils.isNotEmpty(impactedVertices)) {
ret.addAll(impactedVertices);
}
return ret;
}
public List<AtlasVertex> getImpactedVertices(String guid) throws AtlasBaseException {
ScriptEngine scriptEngine = graph.getGremlinScriptEngine();
Bindings bindings = scriptEngine.createBindings();
String query = queryProvider.getQuery(TAG_PROPAGATION_IMPACTED_INSTANCES);
List<AtlasVertex> ret = new ArrayList<>();
bindings.put("g", graph);
bindings.put("guid", guid);
try {
Object resultObj = graph.executeGremlinScript(scriptEngine, bindings, query, false);
if (resultObj instanceof List && CollectionUtils.isNotEmpty((List) resultObj)) {
List<?> results = (List) resultObj;
Object firstElement = results.get(0);
if (firstElement instanceof AtlasVertex) {
ret = (List<AtlasVertex>) results;
}
}
} catch (ScriptException e) {
throw new AtlasBaseException(AtlasErrorCode.GREMLIN_SCRIPT_EXECUTION_FAILED, e);
}
return ret;
}
public List<AtlasVertex> getPropagatedEntityVertices(AtlasVertex classificationVertex) throws AtlasBaseException {
List<AtlasVertex> ret = new ArrayList<>();
if (classificationVertex != null) {
String entityGuid = getClassificationEntityGuid(classificationVertex);
String classificationId = classificationVertex.getIdForDisplay();
List<AtlasVertex> impactedEntityVertices = getAllPropagatedEntityVertices(classificationVertex);
List<AtlasVertex> impactedEntityVerticesWithRestrictions = getImpactedVerticesWithRestrictions(entityGuid, classificationId);
if (impactedEntityVertices.size() > impactedEntityVerticesWithRestrictions.size()) {
ret = (List<AtlasVertex>) CollectionUtils.subtract(impactedEntityVertices, impactedEntityVerticesWithRestrictions);
} else {
ret = (List<AtlasVertex>) CollectionUtils.subtract(impactedEntityVerticesWithRestrictions, impactedEntityVertices);
}
}
return ret;
}
public List<AtlasVertex> getImpactedVerticesWithRestrictions(String guid, String classificationId) throws AtlasBaseException {
return getImpactedVerticesWithRestrictions(guid, classificationId, null);
}
public List<AtlasVertex> getImpactedVerticesWithRestrictions(String guid, String classificationId, String guidRelationshipToExclude) throws AtlasBaseException {
ScriptEngine scriptEngine = graph.getGremlinScriptEngine();
Bindings bindings = scriptEngine.createBindings();
List<AtlasVertex> ret = new ArrayList<>();
String query = queryProvider.getQuery(TAG_PROPAGATION_IMPACTED_INSTANCES_WITH_RESTRICTIONS);
bindings.put("g", graph);
bindings.put("guid", guid);
bindings.put("classificationId", classificationId);
if (guidRelationshipToExclude != null) {
query = queryProvider.getQuery(TAG_PROPAGATION_IMPACTED_INSTANCES_EXCLUDE_RELATIONSHIP);
bindings.put("guidRelationshipToExclude", guidRelationshipToExclude);
}
try {
Object resultObj = graph.executeGremlinScript(scriptEngine, bindings, query, false);
if (resultObj instanceof List && CollectionUtils.isNotEmpty((List) resultObj)) {
List<?> results = (List) resultObj;
Object firstElement = results.get(0);
if (firstElement instanceof AtlasVertex) {
ret = (List<AtlasVertex>) results;
}
}
} catch (ScriptException e) {
throw new AtlasBaseException(AtlasErrorCode.GREMLIN_SCRIPT_EXECUTION_FAILED, e);
}
return ret;
}
public List<AtlasVertex> getImpactedVerticesWithReferences(String guid, String relationshipGuid) throws AtlasBaseException {
ScriptEngine scriptEngine = graph.getGremlinScriptEngine();
Bindings bindings = scriptEngine.createBindings();
String query = queryProvider.getQuery(TAG_PROPAGATION_IMPACTED_INSTANCES_FOR_REMOVAL);
List<AtlasVertex> ret = new ArrayList<>();
bindings.put("g", graph);
bindings.put("guid", guid);
bindings.put("relationshipGuid", relationshipGuid);
try {
Object resultObj = graph.executeGremlinScript(scriptEngine, bindings, query, false);
if (resultObj instanceof List && CollectionUtils.isNotEmpty((List) resultObj)) {
List<?> results = (List) resultObj;
Object firstElement = results.get(0);
if (firstElement instanceof AtlasVertex) {
ret = (List<AtlasVertex>) results;
}
}
} catch (ScriptException e) {
throw new AtlasBaseException(AtlasErrorCode.GREMLIN_SCRIPT_EXECUTION_FAILED, e);
}
return ret;
}
/**
* Finds the Vertices that correspond to the given GUIDs. GUIDs
* that are not found in the graph will not be in the map.
*
* @return GUID to AtlasVertex map with the result.
*/
public Map<String, AtlasVertex> getVerticesForGUIDs(List<String> guids) {
return getVerticesForPropertyValues(Constants.GUID_PROPERTY_KEY, guids);
}
public static void updateModificationMetadata(AtlasVertex vertex) {
AtlasGraphUtilsV2.setEncodedProperty(vertex, MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
AtlasGraphUtilsV2.setEncodedProperty(vertex, MODIFIED_BY_KEY, RequestContext.get().getUser());
}
public static String getQualifiedNameForMapKey(String prefix, String key) {
return prefix + "." + key;
}
public static String getTraitLabel(String typeName, String attrName) {
return attrName;
}
public static String getTraitLabel(String traitName) {
return traitName;
}
public static List<String> getTraitNames(AtlasVertex entityVertex) {
return getTraitNames(entityVertex, false);
}
public static List<String> getPropagatedTraitNames(AtlasVertex entityVertex) {
return getTraitNames(entityVertex, true);
}
public static List<String> getAllTraitNames(AtlasVertex entityVertex) {
return getTraitNames(entityVertex, null);
}
public static List<String> getTraitNames(AtlasVertex entityVertex, Boolean propagated) {
List<String> ret = new ArrayList<>();
AtlasVertexQuery query = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL);
if (propagated != null) {
query = query.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, propagated);
}
Iterable edges = query.edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
ret.add(AtlasGraphUtilsV2.getEncodedProperty(edge, CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, String.class));
}
}
return ret;
}
public static List<AtlasVertex> getClassificationVertices(AtlasEdge edge) {
List<AtlasVertex> ret = new ArrayList<>();
if (edge != null && getStatus(edge) != DELETED) {
PropagateTags propagateTags = getPropagateTags(edge);
AtlasVertex outVertex = edge.getOutVertex();
AtlasVertex inVertex = edge.getInVertex();
if (propagateTags == PropagateTags.ONE_TO_TWO || propagateTags == PropagateTags.BOTH) {
ret.addAll(getPropagationEnabledClassificationVertices(outVertex));
}
if (propagateTags == PropagateTags.TWO_TO_ONE || propagateTags == PropagateTags.BOTH) {
ret.addAll(getPropagationEnabledClassificationVertices(inVertex));
}
}
return ret;
}
public Map<AtlasVertex, List<AtlasVertex>> getClassificationPropagatedEntitiesMapping(List<AtlasVertex> classificationVertices) throws AtlasBaseException {
return getClassificationPropagatedEntitiesMapping(classificationVertices, null);
}
public Map<AtlasVertex, List<AtlasVertex>> getClassificationPropagatedEntitiesMapping(List<AtlasVertex> classificationVertices, String guidRelationshipToExclude) throws AtlasBaseException {
Map<AtlasVertex, List<AtlasVertex>> ret = new HashMap<>();
if (CollectionUtils.isNotEmpty(classificationVertices)) {
for (AtlasVertex classificationVertex : classificationVertices) {
String classificationId = classificationVertex.getIdForDisplay();
String sourceEntityId = getClassificationEntityGuid(classificationVertex);
List<AtlasVertex> entitiesPropagatingTo = getImpactedVerticesWithRestrictions(sourceEntityId, classificationId, guidRelationshipToExclude);
ret.put(classificationVertex, entitiesPropagatingTo);
}
}
return ret;
}
public static List<AtlasVertex> getPropagationEnabledClassificationVertices(AtlasVertex entityVertex) {
List<AtlasVertex> ret = new ArrayList<>();
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
if (edge != null) {
AtlasVertex classificationVertex = edge.getInVertex();
if (isPropagationEnabled(classificationVertex)) {
ret.add(classificationVertex);
}
}
}
}
return ret;
}
public static List<AtlasEdge> getClassificationEdges(AtlasVertex entityVertex) {
return getClassificationEdges(entityVertex, false);
}
public static List<AtlasEdge> getPropagatedClassificationEdges(AtlasVertex entityVertex) {
return getClassificationEdges(entityVertex, true);
}
public static List<AtlasEdge> getAllClassificationEdges(AtlasVertex entityVertex) {
return getClassificationEdges(entityVertex, null);
}
public static List<AtlasEdge> getClassificationEdges(AtlasVertex entityVertex, Boolean propagated) {
List<AtlasEdge> ret = new ArrayList<>();
AtlasVertexQuery query = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL);
if (propagated != null) {
query = query.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, propagated);
}
Iterable edges = query.edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
if (edge != null) {
ret.add(edge);
}
}
}
return ret;
}
public static List<String> getSuperTypeNames(AtlasVertex<?,?> entityVertex) {
ArrayList<String> superTypes = new ArrayList<>();
Collection<String> propertyValues = entityVertex.getPropertyValues(SUPER_TYPES_PROPERTY_KEY, String.class);
if (CollectionUtils.isNotEmpty(propertyValues)) {
for(String value : propertyValues) {
superTypes.add(value);
}
}
return superTypes;
}
public static String getEdgeLabel(AtlasAttribute aInfo) throws AtlasException {
return GraphHelper.EDGE_LABEL_PREFIX + aInfo.getQualifiedName();
}
public static Id getIdFromVertex(String dataTypeName, AtlasVertex vertex) {
return new Id(getGuid(vertex),
getVersion(vertex).intValue(), dataTypeName,
getStateAsString(vertex));
}
public static Id getIdFromVertex(AtlasVertex vertex) {
return getIdFromVertex(getTypeName(vertex), vertex);
}
public static String getRelationshipGuid(AtlasElement element) {
return element.getProperty(Constants.RELATIONSHIP_GUID_PROPERTY_KEY, String.class);
}
public static String getGuid(AtlasElement element) {
return element.<String>getProperty(Constants.GUID_PROPERTY_KEY, String.class);
}
public static String getHomeId(AtlasElement element) {
return element.getProperty(Constants.HOME_ID_KEY, String.class);
}
public static Boolean isProxy(AtlasElement element) {
return element.getProperty(Constants.IS_PROXY_KEY, Boolean.class);
}
public static String getTypeName(AtlasElement element) {
return element.getProperty(ENTITY_TYPE_PROPERTY_KEY, String.class);
}
public static Id.EntityState getState(AtlasElement element) {
String state = getStateAsString(element);
return state == null ? null : Id.EntityState.valueOf(state);
}
public static Long getVersion(AtlasElement element) {
return element.getProperty(Constants.VERSION_PROPERTY_KEY, Long.class);
}
public static String getStateAsString(AtlasElement element) {
return element.getProperty(STATE_PROPERTY_KEY, String.class);
}
public static Status getStatus(AtlasElement element) {
return (getState(element) == Id.EntityState.DELETED) ? Status.DELETED : Status.ACTIVE;
}
public static AtlasRelationship.Status getEdgeStatus(AtlasElement element) {
return (getState(element) == Id.EntityState.DELETED) ? AtlasRelationship.Status.DELETED : AtlasRelationship.Status.ACTIVE;
}
public static String getClassificationName(AtlasVertex classificationVertex) {
return AtlasGraphUtilsV2.getEncodedProperty(classificationVertex, CLASSIFICATION_VERTEX_NAME_KEY, String.class);
}
public static String getClassificationEntityGuid(AtlasVertex classificationVertex) {
return AtlasGraphUtilsV2.getEncodedProperty(classificationVertex, CLASSIFICATION_ENTITY_GUID, String.class);
}
public static Integer getIndexValue(AtlasEdge edge) {
Integer index = edge.getProperty(ATTRIBUTE_INDEX_PROPERTY_KEY, Integer.class);
return (index == null) ? 0: index;
}
public static boolean isPropagatedClassificationEdge(AtlasEdge edge) {
boolean ret = false;
if (edge != null) {
Boolean isPropagated = edge.getProperty(Constants.CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, Boolean.class);
if (isPropagated != null) {
ret = isPropagated.booleanValue();
}
}
return ret;
}
public static boolean isClassificationEdge(AtlasEdge edge) {
boolean ret = false;
if (edge != null) {
String edgeLabel = edge.getLabel();
Boolean isPropagated = edge.getProperty(Constants.CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, Boolean.class);
if (edgeLabel != null && isPropagated != null) {
ret = edgeLabel.equals(CLASSIFICATION_LABEL) && !isPropagated;
}
}
return ret;
}
public static List<String> getBlockedClassificationIds(AtlasEdge edge) {
List<String> ret = null;
if (edge != null) {
List<String> classificationIds = AtlasGraphUtilsV2.getEncodedProperty(edge, RELATIONSHIPTYPE_BLOCKED_PROPAGATED_CLASSIFICATIONS_KEY, List.class);
ret = CollectionUtils.isNotEmpty(classificationIds) ? classificationIds : Collections.emptyList();
}
return ret;
}
public static PropagateTags getPropagateTags(AtlasElement element) {
String propagateTags = element.getProperty(RELATIONSHIPTYPE_TAG_PROPAGATION_KEY, String.class);
return (propagateTags == null) ? null : PropagateTags.valueOf(propagateTags);
}
public static Status getClassificationEntityStatus(AtlasElement element) {
String status = element.getProperty(CLASSIFICATION_ENTITY_STATUS, String.class);
return (status == null) ? null : Status.valueOf(status);
}
//Added conditions in fetching system attributes to handle test failures in GremlinTest where these properties are not set
public static String getCreatedByAsString(AtlasElement element){
return element.getProperty(CREATED_BY_KEY, String.class);
}
public static String getModifiedByAsString(AtlasElement element){
return element.getProperty(MODIFIED_BY_KEY, String.class);
}
public static long getCreatedTime(AtlasElement element){
return element.getProperty(TIMESTAMP_PROPERTY_KEY, Long.class);
}
public static long getModifiedTime(AtlasElement element){
return element.getProperty(MODIFICATION_TIMESTAMP_PROPERTY_KEY, Long.class);
}
public static boolean isActive(AtlasEntity entity) {
return entity != null ? entity.getStatus() == ACTIVE : false;
}
/**
* For the given type, finds an unique attribute and checks if there is an existing instance with the same
* unique value
*
* @param classType
* @param instance
* @return
* @throws AtlasException
*/
public AtlasVertex getVertexForInstanceByUniqueAttribute(AtlasEntityType classType, Referenceable instance)
throws AtlasException {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking if there is an instance with the same unique attributes for instance {}", instance.toShortString());
}
AtlasVertex result = null;
for (AtlasAttribute attributeInfo : classType.getUniqAttributes().values()) {
String propertyKey = attributeInfo.getQualifiedName();
try {
result = findVertex(propertyKey, instance.get(attributeInfo.getName()),
ENTITY_TYPE_PROPERTY_KEY, classType.getTypeName(),
STATE_PROPERTY_KEY, Id.EntityState.ACTIVE.name());
if (LOG.isDebugEnabled()) {
LOG.debug("Found vertex by unique attribute : {}={}", propertyKey, instance.get(attributeInfo.getName()));
}
} catch (EntityNotFoundException e) {
//Its ok if there is no entity with the same unique value
}
}
return result;
}
/**
* Finds vertices that match at least one unique attribute of the instances specified. The AtlasVertex at a given index in the result corresponds
* to the IReferencableInstance at that same index that was passed in. The number of elements in the resultant list is guaranteed to match the
* number of instances that were passed in. If no vertex is found for a given instance, that entry will be null in the resultant list.
*
*
* @param classType
* @param instancesForClass
* @return
* @throws AtlasException
*/
public List<AtlasVertex> getVerticesForInstancesByUniqueAttribute(AtlasEntityType classType, List<? extends Referenceable> instancesForClass) throws AtlasException {
//For each attribute, need to figure out what values to search for and which instance(s)
//those values correspond to.
Map<String, AttributeValueMap> map = new HashMap<String, AttributeValueMap>();
for (AtlasAttribute attributeInfo : classType.getUniqAttributes().values()) {
String propertyKey = attributeInfo.getQualifiedName();
AttributeValueMap mapForAttribute = new AttributeValueMap();
for(int idx = 0; idx < instancesForClass.size(); idx++) {
Referenceable instance = instancesForClass.get(idx);
Object value = instance.get(attributeInfo.getName());
mapForAttribute.put(value, instance, idx);
}
map.put(propertyKey, mapForAttribute);
}
AtlasVertex[] result = new AtlasVertex[instancesForClass.size()];
if(map.isEmpty()) {
//no unique attributes
return Arrays.asList(result);
}
//construct gremlin query
AtlasGraphQuery query = graph.query();
query.has(ENTITY_TYPE_PROPERTY_KEY, classType.getTypeName());
query.has(STATE_PROPERTY_KEY,Id.EntityState.ACTIVE.name());
List<AtlasGraphQuery> orChildren = new ArrayList<AtlasGraphQuery>();
//build up an or expression to find vertices which match at least one of the unique attribute constraints
//For each unique attributes, we add a within clause to match vertices that have a value of that attribute
//that matches the value in some instance.
for(Map.Entry<String, AttributeValueMap> entry : map.entrySet()) {
AtlasGraphQuery orChild = query.createChildQuery();
String propertyName = entry.getKey();
AttributeValueMap valueMap = entry.getValue();
Set<Object> values = valueMap.getAttributeValues();
if(values.size() == 1) {
orChild.has(propertyName, values.iterator().next());
}
else if(values.size() > 1) {
orChild.in(propertyName, values);
}
orChildren.add(orChild);
}
if(orChildren.size() == 1) {
AtlasGraphQuery child = orChildren.get(0);
query.addConditionsFrom(child);
}
else if(orChildren.size() > 1) {
query.or(orChildren);
}
Iterable<AtlasVertex> queryResult = query.vertices();
for(AtlasVertex matchingVertex : queryResult) {
Collection<IndexedInstance> matches = getInstancesForVertex(map, matchingVertex);
for(IndexedInstance wrapper : matches) {
result[wrapper.getIndex()]= matchingVertex;
}
}
return Arrays.asList(result);
}
//finds the instance(s) that correspond to the given vertex
private Collection<IndexedInstance> getInstancesForVertex(Map<String, AttributeValueMap> map, AtlasVertex foundVertex) {
//loop through the unique attributes. For each attribute, check to see if the vertex property that
//corresponds to that attribute has a value from one or more of the instances that were passed in.
for(Map.Entry<String, AttributeValueMap> entry : map.entrySet()) {
String propertyName = entry.getKey();
AttributeValueMap valueMap = entry.getValue();
Object vertexValue = foundVertex.getProperty(propertyName, Object.class);
Collection<IndexedInstance> instances = valueMap.get(vertexValue);
if(instances != null && instances.size() > 0) {
//return first match. Let the underling graph determine if this is a problem
//(i.e. if the other unique attributes change be changed safely to match what
//the user requested).
return instances;
}
//try another attribute
}
return Collections.emptyList();
}
public static List<String> getTypeNames(List<AtlasVertex> vertices) {
List<String> ret = new ArrayList<>();
if (CollectionUtils.isNotEmpty(vertices)) {
for (AtlasVertex vertex : vertices) {
String entityTypeProperty = vertex.getProperty(ENTITY_TYPE_PROPERTY_KEY, String.class);
if (entityTypeProperty != null) {
ret.add(getTypeName(vertex));
}
}
}
return ret;
}
public static AtlasVertex getAssociatedEntityVertex(AtlasVertex classificationVertex) {
AtlasVertex ret = null;
Iterable edges = classificationVertex.query().direction(AtlasEdgeDirection.IN).label(CLASSIFICATION_LABEL)
.has(CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, false)
.has(CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, getTypeName(classificationVertex)).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
if (iterator != null && iterator.hasNext()) {
AtlasEdge edge = iterator.next();
ret = edge.getOutVertex();
}
}
return ret;
}
/**
* Guid and AtlasVertex combo
*/
public static class VertexInfo {
private final AtlasObjectId entity;
private final AtlasVertex vertex;
public VertexInfo(AtlasObjectId entity, AtlasVertex vertex) {
this.entity = entity;
this.vertex = vertex;
}
public AtlasObjectId getEntity() { return entity; }
public AtlasVertex getVertex() {
return vertex;
}
public String getGuid() {
return entity.getGuid();
}
public String getTypeName() {
return entity.getTypeName();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VertexInfo that = (VertexInfo) o;
return Objects.equals(entity, that.entity) &&
Objects.equals(vertex, that.vertex);
}
@Override
public int hashCode() {
return Objects.hash(entity, vertex);
}
}
/*
/**
* Get the GUIDs and vertices for all composite entities owned/contained by the specified root entity AtlasVertex.
* The graph is traversed from the root entity through to the leaf nodes of the containment graph.
*
* @param entityVertex the root entity vertex
* @return set of VertexInfo for all composite entities
* @throws AtlasException
*/
/*
public Set<VertexInfo> getCompositeVertices(AtlasVertex entityVertex) throws AtlasException {
Set<VertexInfo> result = new HashSet<>();
Stack<AtlasVertex> vertices = new Stack<>();
vertices.push(entityVertex);
while (vertices.size() > 0) {
AtlasVertex vertex = vertices.pop();
String typeName = GraphHelper.getTypeName(vertex);
String guid = GraphHelper.getGuid(vertex);
Id.EntityState state = GraphHelper.getState(vertex);
if (state == Id.EntityState.DELETED) {
//If the reference vertex is marked for deletion, skip it
continue;
}
result.add(new VertexInfo(guid, vertex, typeName));
ClassType classType = typeSystem.getDataType(ClassType.class, typeName);
for (AttributeInfo attributeInfo : classType.fieldMapping().fields.values()) {
if (!attributeInfo.isComposite) {
continue;
}
String edgeLabel = GraphHelper.getEdgeLabel(classType, attributeInfo);
switch (attributeInfo.dataType().getTypeCategory()) {
case CLASS:
AtlasEdge edge = getEdgeForLabel(vertex, edgeLabel);
if (edge != null && GraphHelper.getState(edge) == Id.EntityState.ACTIVE) {
AtlasVertex compositeVertex = edge.getInVertex();
vertices.push(compositeVertex);
}
break;
case ARRAY:
IDataType elementType = ((DataTypes.ArrayType) attributeInfo.dataType()).getElemType();
DataTypes.TypeCategory elementTypeCategory = elementType.getTypeCategory();
if (elementTypeCategory != TypeCategory.CLASS) {
continue;
}
Iterator<AtlasEdge> edges = getOutGoingEdgesByLabel(vertex, edgeLabel);
if (edges != null) {
while (edges.hasNext()) {
edge = edges.next();
if (edge != null && GraphHelper.getState(edge) == Id.EntityState.ACTIVE) {
AtlasVertex compositeVertex = edge.getInVertex();
vertices.push(compositeVertex);
}
}
}
break;
case MAP:
DataTypes.MapType mapType = (DataTypes.MapType) attributeInfo.dataType();
DataTypes.TypeCategory valueTypeCategory = mapType.getValueType().getTypeCategory();
if (valueTypeCategory != TypeCategory.CLASS) {
continue;
}
String propertyName = GraphHelper.getQualifiedFieldName(classType, attributeInfo.name);
List<String> keys = vertex.getProperty(propertyName, List.class);
if (keys != null) {
for (String key : keys) {
String mapEdgeLabel = GraphHelper.getQualifiedNameForMapKey(edgeLabel, key);
edge = getEdgeForLabel(vertex, mapEdgeLabel);
if (edge != null && GraphHelper.getState(edge) == Id.EntityState.ACTIVE) {
AtlasVertex compositeVertex = edge.getInVertex();
vertices.push(compositeVertex);
}
}
}
break;
default:
}
}
}
return result;
}
*/
/*
public static Referenceable[] deserializeClassInstances(AtlasTypeRegistry typeRegistry, String entityInstanceDefinition)
throws AtlasException {
try {
JSONArray referableInstances = new JSONArray(entityInstanceDefinition);
Referenceable[] instances = new Referenceable[referableInstances.length()];
for (int index = 0; index < referableInstances.length(); index++) {
Referenceable entityInstance =
AtlasType.fromV1Json(referableInstances.getString(index), Referenceable.class);
Referenceable typedInstrance = getTypedReferenceableInstance(typeRegistry, entityInstance);
instances[index] = typedInstrance;
}
return instances;
} catch(TypeNotFoundException e) {
throw e;
} catch (Exception e) { // exception from deserializer
LOG.error("Unable to deserialize json={}", entityInstanceDefinition, e);
throw new IllegalArgumentException("Unable to deserialize json", e);
}
}
public static Referenceable getTypedReferenceableInstance(AtlasTypeRegistry typeRegistry, Referenceable entityInstance)
throws AtlasException {
final String entityTypeName = ParamChecker.notEmpty(entityInstance.getTypeName(), "Entity type cannot be null");
AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entityTypeName);
//Both assigned id and values are required for full update
//classtype.convert() will remove values if id is assigned. So, set temp id, convert and
// then replace with original id
Id origId = entityInstance.getId();
entityInstance.setId(new Id(entityInstance.getTypeName()));
Referenceable typedInstrance = new Referenceable(entityInstance);
typedInstrance.setId(origId);
return typedInstrance;
}
*/
public static boolean isInternalType(AtlasVertex vertex) {
return vertex != null && isInternalType(getTypeName(vertex));
}
public static boolean isInternalType(String typeName) {
return typeName != null && typeName.startsWith(Constants.INTERNAL_PROPERTY_KEY_PREFIX);
}
public static List<Object> getArrayElementsProperty(AtlasType elementType, AtlasVertex instanceVertex, AtlasAttribute attribute) {
String propertyName = attribute.getVertexPropertyName();
if (isReference(elementType)) {
return (List) getCollectionElementsUsingRelationship(instanceVertex, attribute);
} else {
return (List) instanceVertex.getListProperty(propertyName);
}
}
public static Map<String, Object> getMapElementsProperty(AtlasMapType mapType, AtlasVertex instanceVertex, String propertyName, AtlasAttribute attribute) {
AtlasType mapValueType = mapType.getValueType();
if (isReference(mapValueType)) {
return getReferenceMap(instanceVertex, attribute);
} else {
return (Map) instanceVertex.getProperty(propertyName, Map.class);
}
}
// map elements for reference types - AtlasObjectId, AtlasStruct
public static Map<String, Object> getReferenceMap(AtlasVertex instanceVertex, AtlasAttribute attribute) {
Map<String, Object> ret = new HashMap<>();
List<AtlasEdge> referenceEdges = getCollectionElementsUsingRelationship(instanceVertex, attribute);
for (AtlasEdge edge : referenceEdges) {
String key = edge.getProperty(ATTRIBUTE_KEY_PROPERTY_KEY, String.class);
if (StringUtils.isNotEmpty(key)) {
ret.put(key, edge);
}
}
return ret;
}
public static List<AtlasEdge> getMapValuesUsingRelationship(AtlasVertex vertex, AtlasAttribute attribute) {
String edgeLabel = attribute.getRelationshipEdgeLabel();
AtlasRelationshipEdgeDirection edgeDirection = attribute.getRelationshipEdgeDirection();
Iterator<AtlasEdge> edgesForLabel = getEdgesForLabel(vertex, edgeLabel, edgeDirection);
return (List<AtlasEdge>) IteratorUtils.toList(edgesForLabel);
}
// map elements for primitive types
public static Map<String, Object> getPrimitiveMap(AtlasVertex instanceVertex, String propertyName) {
Map<String, Object> ret = instanceVertex.getProperty(encodePropertyKey(propertyName), Map.class);
if (ret == null) {
ret = new HashMap<>();
}
return ret;
}
public static List<AtlasEdge> getCollectionElementsUsingRelationship(AtlasVertex vertex, AtlasAttribute attribute) {
List<AtlasEdge> ret;
String edgeLabel = attribute.getRelationshipEdgeLabel();
AtlasRelationshipEdgeDirection edgeDirection = attribute.getRelationshipEdgeDirection();
Iterator<AtlasEdge> edgesForLabel = getEdgesForLabel(vertex, edgeLabel, edgeDirection);
ret = IteratorUtils.toList(edgesForLabel);
sortCollectionElements(attribute, ret);
return ret;
}
private static void sortCollectionElements(AtlasAttribute attribute, List<AtlasEdge> edges) {
// sort array elements based on edge index
if (attribute.getAttributeType() instanceof AtlasArrayType && CollectionUtils.isNotEmpty(edges)) {
Collections.sort(edges, (e1, e2) -> {
Integer e1Index = getIndexValue(e1);
Integer e2Index = getIndexValue(e2);
return e1Index.compareTo(e2Index);
});
}
}
public static void dumpToLog(final AtlasGraph<?,?> graph) {
LOG.debug("*******************Graph Dump****************************");
LOG.debug("Vertices of {}", graph);
for (AtlasVertex vertex : graph.getVertices()) {
LOG.debug(vertexString(vertex));
}
LOG.debug("Edges of {}", graph);
for (AtlasEdge edge : graph.getEdges()) {
LOG.debug(edgeString(edge));
}
LOG.debug("*******************Graph Dump****************************");
}
public static String string(Referenceable instance) {
return String.format("entity[type=%s guid=%s]", instance.getTypeName(), instance.getId()._getId());
}
public static String string(AtlasVertex<?,?> vertex) {
if(vertex == null) {
return "vertex[null]";
} else {
if (LOG.isDebugEnabled()) {
return getVertexDetails(vertex);
} else {
return String.format("vertex[id=%s]", vertex.getIdForDisplay());
}
}
}
public static String getVertexDetails(AtlasVertex<?,?> vertex) {
return String.format("vertex[id=%s type=%s guid=%s]", vertex.getIdForDisplay(), getTypeName(vertex),
getGuid(vertex));
}
public static String string(AtlasEdge<?,?> edge) {
if(edge == null) {
return "edge[null]";
} else {
if (LOG.isDebugEnabled()) {
return getEdgeDetails(edge);
} else {
return String.format("edge[id=%s]", edge.getIdForDisplay());
}
}
}
public static String getEdgeDetails(AtlasEdge<?,?> edge) {
return String.format("edge[id=%s label=%s from %s -> to %s]", edge.getIdForDisplay(), edge.getLabel(),
string(edge.getOutVertex()), string(edge.getInVertex()));
}
@VisibleForTesting
//Keys copied from com.thinkaurelius.titan.graphdb.types.StandardRelationTypeMaker
//Titan checks that these chars are not part of any keys. So, encoding...
public static BiMap<String, String> RESERVED_CHARS_ENCODE_MAP =
HashBiMap.create(new HashMap<String, String>() {{
put("{", "_o");
put("}", "_c");
put("\"", "_q");
put("$", "_d");
put("%", "_p");
}});
public static String encodePropertyKey(String key) {
if (StringUtils.isBlank(key)) {
return key;
}
for (String str : RESERVED_CHARS_ENCODE_MAP.keySet()) {
key = key.replace(str, RESERVED_CHARS_ENCODE_MAP.get(str));
}
return key;
}
public static String decodePropertyKey(String key) {
if (StringUtils.isBlank(key)) {
return key;
}
for (String encodedStr : RESERVED_CHARS_ENCODE_MAP.values()) {
key = key.replace(encodedStr, RESERVED_CHARS_ENCODE_MAP.inverse().get(encodedStr));
}
return key;
}
public Object getVertexId(String guid) throws EntityNotFoundException {
AtlasVertex instanceVertex = getVertexForGUID(guid);
Object instanceVertexId = instanceVertex.getId();
return instanceVertexId;
}
/*
public static AttributeInfo getAttributeInfoForSystemAttributes(String field) {
switch (field) {
case Constants.STATE_PROPERTY_KEY:
case Constants.GUID_PROPERTY_KEY:
case Constants.CREATED_BY_KEY:
case Constants.MODIFIED_BY_KEY:
return TypesUtil.newAttributeInfo(field, DataTypes.STRING_TYPE);
case Constants.TIMESTAMP_PROPERTY_KEY:
case Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY:
return TypesUtil.newAttributeInfo(field, DataTypes.DATE_TYPE);
}
return null;
}
*/
public static boolean elementExists(AtlasElement v) {
return v != null && v.exists();
}
public static void setListPropertyFromElementIds(AtlasVertex<?, ?> instanceVertex, String propertyName,
List<AtlasElement> elements) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
instanceVertex.setPropertyFromElementsIds(actualPropertyName, elements);
}
public static void setPropertyFromElementId(AtlasVertex<?, ?> instanceVertex, String propertyName,
AtlasElement value) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
instanceVertex.setPropertyFromElementId(actualPropertyName, value);
}
public static void setListProperty(AtlasVertex instanceVertex, String propertyName, ArrayList<String> value) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
instanceVertex.setListProperty(actualPropertyName, value);
}
public static List<String> getListProperty(AtlasVertex instanceVertex, String propertyName) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
return instanceVertex.getListProperty(actualPropertyName);
}
private String getConditionString(Object[] args) {
StringBuilder condition = new StringBuilder();
for (int i = 0; i < args.length; i+=2) {
condition.append(args[i]).append(" = ").append(args[i+1]).append(", ");
}
return condition.toString();
}
/**
* Get relationshipDef name from entityType using relationship attribute.
* if more than one relationDefs are returned for an attribute.
* e.g. hive_column.table
*
* hive_table.columns -> hive_column.table
* hive_table.partitionKeys -> hive_column.table
*
* resolve by comparing all incoming edges typename with relationDefs name returned for an attribute
* to pick the right relationshipDef name
*/
public String getRelationshipDefName(AtlasVertex entityVertex, AtlasEntityType entityType, String attributeName) {
AtlasRelationshipDef relationshipDef = getRelationshipDef(entityVertex, entityType, attributeName);
return (relationshipDef != null) ? relationshipDef.getName() : null;
}
public AtlasRelationshipDef getRelationshipDef(AtlasVertex entityVertex, AtlasEntityType entityType, String attributeName) {
List<AtlasRelationshipType> relationshipTypes = entityType.getRelationshipAttributeType(attributeName);
AtlasRelationshipDef ret = null;
if (relationshipTypes.size() > 1) {
Iterator<AtlasEdge> iter = entityVertex.getEdges(AtlasEdgeDirection.IN).iterator();
while (iter.hasNext() && ret == null) {
String edgeTypeName = AtlasGraphUtilsV2.getTypeName(iter.next());
for (AtlasRelationshipType relationType : relationshipTypes) {
AtlasRelationshipDef relationshipDef = relationType.getRelationshipDef();
if (StringUtils.equals(edgeTypeName, relationshipDef.getName())) {
ret = relationshipDef;
break;
}
}
}
if (ret == null) {
ret = relationshipTypes.get(0).getRelationshipDef();
}
} else {
//relationshipTypes will have at least one relationshipDef
ret = relationshipTypes.get(0).getRelationshipDef();
}
return ret;
}
public static boolean isRelationshipEdge(AtlasEdge edge) {
if (edge == null) {
return false;
}
String edgeLabel = edge.getLabel();
return StringUtils.isNotEmpty(edge.getLabel()) ? edgeLabel.startsWith("r:") : false;
}
public static AtlasObjectId getReferenceObjectId(AtlasEdge edge, AtlasRelationshipEdgeDirection relationshipDirection,
AtlasVertex parentVertex) {
AtlasObjectId ret = null;
if (relationshipDirection == OUT) {
ret = getAtlasObjectIdForInVertex(edge);
} else if (relationshipDirection == IN) {
ret = getAtlasObjectIdForOutVertex(edge);
} else if (relationshipDirection == BOTH){
// since relationship direction is BOTH, edge direction can be inward or outward
// compare with parent entity vertex and pick the right reference vertex
if (verticesEquals(parentVertex, edge.getOutVertex())) {
ret = getAtlasObjectIdForInVertex(edge);
} else {
ret = getAtlasObjectIdForOutVertex(edge);
}
}
return ret;
}
public static AtlasObjectId getAtlasObjectIdForOutVertex(AtlasEdge edge) {
return new AtlasObjectId(getGuid(edge.getOutVertex()), getTypeName(edge.getOutVertex()));
}
public static AtlasObjectId getAtlasObjectIdForInVertex(AtlasEdge edge) {
return new AtlasObjectId(getGuid(edge.getInVertex()), getTypeName(edge.getInVertex()));
}
private static boolean verticesEquals(AtlasVertex vertexA, AtlasVertex vertexB) {
return StringUtils.equals(getGuid(vertexB), getGuid(vertexA));
}
public static boolean getDefaultRemovePropagations() {
return removePropagations;
}
}