Repository: atlas Updated Branches: refs/heads/master 993180309 -> 0f689faaa
ATLAS-2510: Add support to disable/enable propagated classification in entity Project: http://git-wip-us.apache.org/repos/asf/atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/0f689faa Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/0f689faa Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/0f689faa Branch: refs/heads/master Commit: 0f689faaa5ef6433ecb39d9f0ee8c4cf8a48b8eb Parents: 9931803 Author: Sarath Subramanian <[email protected]> Authored: Mon Mar 26 22:28:39 2018 -0700 Committer: Sarath Subramanian <[email protected]> Committed: Mon Mar 26 22:28:39 2018 -0700 ---------------------------------------------------------------------- .../org/apache/atlas/repository/Constants.java | 1 + .../java/org/apache/atlas/AtlasErrorCode.java | 1 + .../model/instance/AtlasClassification.java | 1 + .../atlas/model/instance/AtlasEntity.java | 23 ++- .../org/apache/atlas/query/GremlinClause.java | 2 +- .../atlas/repository/graph/GraphHelper.java | 162 +++++++++++-------- .../store/graph/AtlasEntityStore.java | 2 + .../store/graph/v1/AtlasEntityStoreV1.java | 17 ++ .../store/graph/v1/DeleteHandlerV1.java | 13 +- .../store/graph/v1/EntityGraphMapper.java | 64 +++++++- .../store/graph/v1/EntityGraphRetriever.java | 74 ++++++--- .../atlas/query/GremlinQueryComposerTest.java | 12 +- .../org/apache/atlas/web/rest/EntityREST.java | 46 ++++++ 13 files changed, 306 insertions(+), 112 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/common/src/main/java/org/apache/atlas/repository/Constants.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/repository/Constants.java b/common/src/main/java/org/apache/atlas/repository/Constants.java index 605742d..310dddb 100644 --- a/common/src/main/java/org/apache/atlas/repository/Constants.java +++ b/common/src/main/java/org/apache/atlas/repository/Constants.java @@ -121,6 +121,7 @@ public final class Constants { public static final String CLASSIFICATION_VERTEX_PROPAGATE_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "propagate"; public static final String CLASSIFICATION_EDGE_NAME_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "name"; public static final String CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "isPropagated"; + public static final String CLASSIFICATION_EDGE_STATE_PROPERTY_KEY = STATE_PROPERTY_KEY; public static final String CLASSIFICATION_LABEL = "classifiedAs"; private Constants() { http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java index 4a86670..997ac68 100644 --- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java +++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java @@ -127,6 +127,7 @@ public enum AtlasErrorCode { CLASSIFICATION_NOT_ASSOCIATED_WITH_ENTITY(400, "ATLAS-400-00-06D", "Classification {0} is not associated with entity"), NO_CLASSIFICATIONS_FOUND_FOR_ENTITY(400, "ATLAS-400-00-06E", "No classifications associated with entity: {0}"), INVALID_CLASSIFICATION_PARAMS(400, "ATLAS-400-00-06F", "Invalid classification parameters passed for {0} operation for entity: {1}"), + PROPAGATED_CLASSIFICATION_NOT_ASSOCIATED_WITH_ENTITY(400, "ATLAS-400-00-070", "Propagated classification {0} is not associated with entity"), UNAUTHORIZED_ACCESS(403, "ATLAS-403-00-001", "{0} is not authorized to perform {1}"), http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/intg/src/main/java/org/apache/atlas/model/instance/AtlasClassification.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/model/instance/AtlasClassification.java b/intg/src/main/java/org/apache/atlas/model/instance/AtlasClassification.java index 008314b..bf4f469 100644 --- a/intg/src/main/java/org/apache/atlas/model/instance/AtlasClassification.java +++ b/intg/src/main/java/org/apache/atlas/model/instance/AtlasClassification.java @@ -57,6 +57,7 @@ public class AtlasClassification extends AtlasStruct implements Serializable { private boolean propagate = true; private List<TimeBoundary> validityPeriods = null; + public enum PropagationState { ACTIVE, DELETED } public AtlasClassification() { this(null, null); http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java index fce46da..3954319 100644 --- a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java +++ b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java @@ -67,7 +67,6 @@ public class AtlasEntity extends AtlasStruct implements Serializable { public static final String KEY_UPDATE_TIME = "updateTime"; public static final String KEY_VERSION = "version"; - /** * Status of the entity - can be active or deleted. Deleted entities are not removed from Atlas store. */ @@ -83,6 +82,7 @@ public class AtlasEntity extends AtlasStruct implements Serializable { private Map<String, Object> relationshipAttributes; private List<AtlasClassification> classifications; + private List<AtlasClassification> propagationDisabledClassifications; @JsonIgnore private static AtomicLong s_nextId = new AtomicLong(System.nanoTime()); @@ -165,6 +165,7 @@ public class AtlasEntity extends AtlasStruct implements Serializable { setUpdateTime(other.getUpdateTime()); setVersion(other.getVersion()); setClassifications(other.getClassifications()); + setPropagationDisabledClassifications(other.getPropagationDisabledClassifications()); } } @@ -259,6 +260,14 @@ public class AtlasEntity extends AtlasStruct implements Serializable { public void setClassifications(List<AtlasClassification> classifications) { this.classifications = classifications; } + public List<AtlasClassification> getPropagationDisabledClassifications() { + return propagationDisabledClassifications; + } + + public void setPropagationDisabledClassifications(List<AtlasClassification> propagationDisabledClassifications) { + this.propagationDisabledClassifications = propagationDisabledClassifications; + } + public void addClassifications(List<AtlasClassification> classifications) { List<AtlasClassification> c = this.classifications; @@ -279,6 +288,7 @@ public class AtlasEntity extends AtlasStruct implements Serializable { setCreateTime(null); setUpdateTime(null); setClassifications(null); + setPropagationDisabledClassifications(null); } private static String nextInternalId() { @@ -306,7 +316,9 @@ public class AtlasEntity extends AtlasStruct implements Serializable { sb.append(", classifications=["); AtlasBaseTypeDef.dumpObjects(classifications, sb); sb.append(']'); - sb.append(", "); + sb.append(", propagationDisabledClassifications=["); + AtlasBaseTypeDef.dumpObjects(propagationDisabledClassifications, sb); + sb.append(']'); sb.append('}'); return sb; @@ -327,13 +339,14 @@ public class AtlasEntity extends AtlasStruct implements Serializable { Objects.equals(updateTime, that.updateTime) && Objects.equals(version, that.version) && Objects.equals(relationshipAttributes, that.relationshipAttributes) && - Objects.equals(classifications, that.classifications); + Objects.equals(classifications, that.classifications) && + Objects.equals(propagationDisabledClassifications, that.propagationDisabledClassifications); } @Override public int hashCode() { return Objects.hash(super.hashCode(), guid, status, createdBy, updatedBy, createTime, updateTime, version, - relationshipAttributes, classifications); + relationshipAttributes, classifications, propagationDisabledClassifications); } @Override @@ -715,4 +728,4 @@ public class AtlasEntity extends AtlasStruct implements Serializable { super(list, startIndex, pageSize, totalCount, sortType, sortBy); } } -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/main/java/org/apache/atlas/query/GremlinClause.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/query/GremlinClause.java b/repository/src/main/java/org/apache/atlas/query/GremlinClause.java index 454b343..087bcc6 100644 --- a/repository/src/main/java/org/apache/atlas/query/GremlinClause.java +++ b/repository/src/main/java/org/apache/atlas/query/GremlinClause.java @@ -46,7 +46,7 @@ enum GremlinClause { TEXT_CONTAINS("has('%s', org.janusgraph.core.attribute.Text.textRegex(%s))"), TEXT_PREFIX("has('%s', org.janusgraph.core.attribute.Text.textPrefix(%s))"), TEXT_SUFFIX("has('%s', org.janusgraph.core.attribute.Text.textRegex(\".*\" + %s))"), - TRAIT("outE('classifiedAs').has('__name', within('%s')).outV()"), + TRAIT("outE('classifiedAs').has('__name', within('%s')).has('__state', 'ACTIVE').outV()"), SELECT_NOOP_FN("def f(r){ r }; "), SELECT_FN("def f(r){ t=[[%s]]; %s r.each({t.add([%s])}); t.unique(); }; "), SELECT_ONLY_AGG_FN("def f(r){ t=[[%s]]; %s t.add([%s]); t;}; "), http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java index bfb5a71..0c63cec 100755 --- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java +++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java @@ -26,6 +26,7 @@ import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.AtlasException; import org.apache.atlas.RequestContextV1; import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.instance.AtlasClassification; import org.apache.atlas.model.instance.AtlasEntity.Status; import org.apache.atlas.model.instance.AtlasObjectId; import org.apache.atlas.model.instance.AtlasRelationship; @@ -73,8 +74,9 @@ 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.repository.Constants.CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY; +import static org.apache.atlas.repository.Constants.CLASSIFICATION_EDGE_STATE_PROPERTY_KEY; +import static org.apache.atlas.repository.Constants.CLASSIFICATION_ENTITY_GUID; 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_PROPAGATE_KEY; @@ -190,6 +192,7 @@ public final class GraphHelper { if (ret != null) { AtlasGraphUtilsV1.setProperty(ret, CLASSIFICATION_EDGE_NAME_PROPERTY_KEY, getTypeName(classificationVertex)); AtlasGraphUtilsV1.setProperty(ret, CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY, isPropagated); + AtlasGraphUtilsV1.setProperty(ret, CLASSIFICATION_EDGE_STATE_PROPERTY_KEY, AtlasClassification.PropagationState.ACTIVE); } return ret; @@ -299,26 +302,6 @@ public final class GraphHelper { return (AtlasEdge) findElement(false, args); } - public static boolean edgeExists(AtlasVertex outVertex, AtlasVertex inVertex, String edgeLabel) { - boolean ret = false; - Iterator<AtlasEdge> edges = getAdjacentEdgesByLabel(inVertex, AtlasEdgeDirection.IN, edgeLabel); - - while (edges != null && edges.hasNext()) { - AtlasEdge edge = edges.next(); - - if (edge.getOutVertex().equals(outVertex)) { - Status edgeState = getStatus(edge); - - if (edgeState == null || edgeState == ACTIVE) { - ret = true; - break; - } - } - } - - return ret; - } - private AtlasElement findElement(boolean isVertexSearch, Object... args) throws EntityNotFoundException { AtlasGraphQuery query = graph.query(); @@ -395,54 +378,83 @@ public final class GraphHelper { } public static AtlasVertex getClassificationVertex(AtlasVertex entityVertex, String classificationName) { - AtlasVertex ret = null; - AtlasEdge edge = getClassificationEdge(entityVertex, 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 (edge != null) { - ret = edge.getInVertex(); + if (iterator.hasNext()) { + AtlasEdge edge = iterator.next(); + + ret = (edge != null) ? edge.getInVertex() : null; + } } return ret; } - public static AtlasEdge getClassificationEdge(AtlasVertex entityVertex, String classificationName) { + 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, classificationName).edges(); + .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 : null; + ret = (edge != null && edge.getInVertex().equals(classificationVertex)) ? edge : null; } } return ret; } - public static List<String> getPropagatedEntities(AtlasVertex classificationVertex) { - List<String> ret = new ArrayList<>(); - List<AtlasVertex> entityVertices = getPropagatedEntityVertices(classificationVertex); + 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(); - if (CollectionUtils.isNotEmpty(entityVertices)) { - for (AtlasVertex entityVertex : entityVertices) { - ret.add(getGuid(entityVertex)); + while (iterator.hasNext()) { + AtlasEdge edge = iterator.next(); + AtlasVertex classificationVertex = (edge != null) ? edge.getInVertex() : null; + + if (classificationVertex != null) { + String guid = AtlasGraphUtilsV1.getProperty(classificationVertex, CLASSIFICATION_ENTITY_GUID, String.class); + + if (StringUtils.equals(guid, associatedEntityGuid)) { + ret = edge; + break; + } + } } } return ret; } - public static List<AtlasVertex> getPropagatedEntityVertices(AtlasVertex classificationVertex) { - List<AtlasVertex> ret = new ArrayList<>(); - List<AtlasEdge> propagatedEdges = getPropagatedEdges(classificationVertex); + 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 (CollectionUtils.isNotEmpty(propagatedEdges)) { - for (AtlasEdge propagatedEdge : propagatedEdges) { - ret.add(propagatedEdge.getOutVertex()); + if (edge != null && edge.getInVertex().equals(classificationVertex)) { + ret = edge; + break; + } } } @@ -676,21 +688,28 @@ public final class GraphHelper { vertex.addProperty(actualPropertyName, value); } - /** - * Adds an additional value to a multi-property (LIST). - * - * @param vertex - * @param propertyName - * @param value - */ - public static void addListProperty(AtlasVertex vertex, String propertyName, Object value) { - String actualPropertyName = GraphHelper.encodePropertyKey(propertyName); + public static void addToPropagatedTraitNames(AtlasVertex entityVertex, String classificationName) { + String actualPropertyName = GraphHelper.encodePropertyKey(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY); if (LOG.isDebugEnabled()) { - LOG.debug("Adding property {} = \"{}\" to vertex {}", actualPropertyName, value, string(vertex)); + LOG.debug("Adding property {} = \"{}\" to vertex {}", actualPropertyName, classificationName, string(entityVertex)); } - vertex.addListProperty(actualPropertyName, value); + entityVertex.addListProperty(actualPropertyName, 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); + } + } } /** @@ -1014,6 +1033,33 @@ public final class GraphHelper { return (getState(element) == Id.EntityState.DELETED) ? AtlasRelationship.Status.DELETED : AtlasRelationship.Status.ACTIVE; } + public static AtlasClassification.PropagationState getClassificationEdgeState(AtlasEdge edge) { + AtlasClassification.PropagationState ret = null; + + if (edge != null) { + String state = edge.getProperty(Constants.CLASSIFICATION_EDGE_STATE_PROPERTY_KEY, String.class); + + ret = (StringUtils.isEmpty(state)) ? AtlasClassification.PropagationState.ACTIVE : + AtlasClassification.PropagationState.valueOf(state); + } + + return ret; + } + + 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 PropagateTags getPropagateTags(AtlasElement element) { String propagateTags = element.getProperty(Constants.RELATIONSHIPTYPE_TAG_PROPAGATION_KEY, String.class); @@ -1661,18 +1707,4 @@ public final class GraphHelper { private static boolean verticesEquals(AtlasVertex vertexA, AtlasVertex vertexB) { return StringUtils.equals(getGuid(vertexB), getGuid(vertexA)); } - - public static void removePropagatedTraitNameFromVertex(AtlasVertex entityVertex, String propagatedTraitName) { - List<String> propagatedTraitNames = getTraitNames(entityVertex, true); - - if (CollectionUtils.isNotEmpty(propagatedTraitNames) && propagatedTraitNames.contains(propagatedTraitName)) { - propagatedTraitNames.remove(propagatedTraitName); - - entityVertex.removeProperty(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY); - - for (String pTraitName : propagatedTraitNames) { - GraphHelper.addListProperty(entityVertex, PROPAGATED_TRAIT_NAMES_PROPERTY_KEY, pTraitName); - } - } - } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java index 79e8e3e..eb825c4 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java @@ -157,4 +157,6 @@ public interface AtlasEntityStore { List<AtlasClassification> getClassifications(String guid) throws AtlasBaseException; AtlasClassification getClassification(String guid, String classificationName) throws AtlasBaseException; + + void setPropagatedClassificationState(String guid, String classificationName, String sourceEntityGuid, boolean disablePropagation) throws AtlasBaseException; } http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java index b5461d4..6fe8570 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java @@ -468,6 +468,23 @@ public class AtlasEntityStoreV1 implements AtlasEntityStore { @Override @GraphTransaction + public void setPropagatedClassificationState(String entityGuid, String classificationName, String sourceEntityGuid, boolean disablePropagation) throws AtlasBaseException { + AtlasEntityHeader entityHeader = entityRetriever.toAtlasEntityHeaderWithClassifications(entityGuid); + + AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_UPDATE_CLASSIFICATION, entityHeader, new AtlasClassification(classificationName)), + "change propagated classification state: guid=", entityGuid, ", classification=", classificationName); + + if (LOG.isDebugEnabled()) { + LOG.debug("Toggle propagated classification={}, sourceEntityGuid={} for entity={}, disablePropagation={}", classificationName, sourceEntityGuid, entityGuid, disablePropagation); + } + + GraphTransactionInterceptor.lockObjectAndReleasePostCommit(entityGuid); + + entityGraphMapper.setPropagatedClassificationState(entityGuid, classificationName, sourceEntityGuid, disablePropagation); + } + + @Override + @GraphTransaction public void deleteClassifications(final String guid, final List<String> classificationNames) throws AtlasBaseException { if (StringUtils.isEmpty(guid)) { throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "Guid(s) not specified"); http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java index 19ac620..6386bcb 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java @@ -41,18 +41,19 @@ import org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdg import org.apache.atlas.type.AtlasType; import org.apache.atlas.type.AtlasTypeRegistry; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; +import static org.apache.atlas.model.instance.AtlasClassification.PropagationState.ACTIVE; import static org.apache.atlas.model.instance.AtlasEntity.Status.DELETED; import static org.apache.atlas.repository.Constants.CLASSIFICATION_LABEL; import static org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPERTY_KEY; import static org.apache.atlas.repository.graph.GraphHelper.EDGE_LABEL_PREFIX; -import static org.apache.atlas.repository.graph.GraphHelper.addListProperty; -import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdge; +import static org.apache.atlas.repository.graph.GraphHelper.addToPropagatedTraitNames; +import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdgeState; import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdges; import static org.apache.atlas.repository.graph.GraphHelper.getPropagatedEdges; import static org.apache.atlas.repository.graph.GraphHelper.getTraitNames; @@ -367,7 +368,9 @@ public abstract class DeleteHandlerV1 { getTypeName(propagatedEntityVertex), GraphHelper.getGuid(propagatedEntityVertex), CLASSIFICATION_LABEL); } - removeFromPropagatedTraitNames(propagatedEntityVertex, classificationName); + if (getClassificationEdgeState(propagatedEdge) == ACTIVE) { + removeFromPropagatedTraitNames(propagatedEntityVertex, classificationName); + } deleteEdge(propagatedEdge, true); @@ -390,7 +393,7 @@ public abstract class DeleteHandlerV1 { entityVertex.removeProperty(PROPAGATED_TRAIT_NAMES_PROPERTY_KEY); for (String propagatedTraitName : propagatedTraitNames) { - addListProperty(entityVertex, PROPAGATED_TRAIT_NAMES_PROPERTY_KEY, propagatedTraitName); + addToPropagatedTraitNames(entityVertex, propagatedTraitName); } } } http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java index c76f640..737e933 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java @@ -25,6 +25,7 @@ import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.model.TimeBoundary; import org.apache.atlas.model.TypeCategory; import org.apache.atlas.model.instance.AtlasClassification; +import org.apache.atlas.model.instance.AtlasClassification.PropagationState; import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; import org.apache.atlas.model.instance.AtlasEntityHeader; @@ -74,20 +75,23 @@ import static org.apache.atlas.model.instance.EntityMutations.EntityOperation.DE import static org.apache.atlas.model.instance.EntityMutations.EntityOperation.PARTIAL_UPDATE; import static org.apache.atlas.model.instance.EntityMutations.EntityOperation.UPDATE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef.Cardinality.SET; +import static org.apache.atlas.repository.Constants.CLASSIFICATION_EDGE_STATE_PROPERTY_KEY; +import static org.apache.atlas.repository.Constants.CLASSIFICATION_ENTITY_GUID; import static org.apache.atlas.repository.Constants.CLASSIFICATION_LABEL; -import static org.apache.atlas.repository.Constants.PROPAGATED_TRAIT_NAMES_PROPERTY_KEY; import static org.apache.atlas.repository.Constants.STATE_PROPERTY_KEY; import static org.apache.atlas.repository.Constants.TRAIT_NAMES_PROPERTY_KEY; -import static org.apache.atlas.repository.graph.GraphHelper.addListProperty; +import static org.apache.atlas.repository.graph.GraphHelper.addToPropagatedTraitNames; import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdge; +import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdgeState; import static org.apache.atlas.repository.graph.GraphHelper.getClassificationVertex; -import static org.apache.atlas.repository.graph.GraphHelper.getPropagatedEntities; +import static org.apache.atlas.repository.graph.GraphHelper.getPropagatedClassificationEdge; import static org.apache.atlas.repository.graph.GraphHelper.getTraitLabel; import static org.apache.atlas.repository.graph.GraphHelper.getTraitNames; import static org.apache.atlas.repository.graph.GraphHelper.getTypeName; import static org.apache.atlas.repository.graph.GraphHelper.getTypeNames; import static org.apache.atlas.repository.graph.GraphHelper.isPropagationEnabled; import static org.apache.atlas.repository.graph.GraphHelper.isRelationshipEdge; +import static org.apache.atlas.repository.graph.GraphHelper.removeFromPropagatedTraitNames; import static org.apache.atlas.repository.graph.GraphHelper.string; import static org.apache.atlas.repository.graph.GraphHelper.updateModificationMetadata; import static org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1.getIdFromVertex; @@ -1443,10 +1447,10 @@ public class EntityGraphMapper { // remove classifications from associated entity if (LOG.isDebugEnabled()) { LOG.debug("Removing classification: [{}] from: [{}][{}] with edge label: [{}]", classificationName, - getTypeName(entityVertex), entityGuid, CLASSIFICATION_LABEL); + getTypeName(entityVertex), entityGuid, CLASSIFICATION_LABEL); } - AtlasEdge edge = getClassificationEdge(entityVertex, classificationName); + AtlasEdge edge = getClassificationEdge(entityVertex, classificationVertex); deleteHandler.deleteEdgeReference(edge, CLASSIFICATION, false, true, entityVertex); @@ -1626,6 +1630,46 @@ public class EntityGraphMapper { } } + public void setPropagatedClassificationState(String entityGuid, String classificationName, String sourceEntityGuid, boolean disablePropagation) throws AtlasBaseException { + AtlasVertex entityVertex = AtlasGraphUtilsV1.findByGuid(entityGuid); + + if (entityVertex == null) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, entityGuid); + } + + AtlasEdge propagatedEdge = getPropagatedClassificationEdge(entityVertex, classificationName, sourceEntityGuid); + + if (propagatedEdge == null) { + throw new AtlasBaseException(AtlasErrorCode.PROPAGATED_CLASSIFICATION_NOT_ASSOCIATED_WITH_ENTITY, classificationName); + } + + PropagationState currentState = getClassificationEdgeState(propagatedEdge); + PropagationState updatedState = (disablePropagation) ? PropagationState.DELETED : PropagationState.ACTIVE; + + if (currentState != updatedState) { + AtlasGraphUtilsV1.setProperty(propagatedEdge, CLASSIFICATION_EDGE_STATE_PROPERTY_KEY, updatedState); + + if (disablePropagation) { + removeFromPropagatedTraitNames(entityVertex, classificationName); + } else { + addToPropagatedTraitNames(entityVertex, classificationName); + } + + updateModificationMetadata(entityVertex); + + AtlasEntityWithExtInfo entityWithExtInfo = instanceConverter.getAndCacheEntity(entityGuid); + AtlasEntity entity = (entityWithExtInfo != null) ? entityWithExtInfo.getEntity() : null; + + if (updatedState == PropagationState.DELETED) { + entityChangeNotifier.onClassificationDeletedFromEntity(entity, Collections.singletonList(classificationName)); + } else { + AtlasClassification classification = entityRetriever.toAtlasClassification(propagatedEdge.getInVertex()); + + entityChangeNotifier.onClassificationAddedToEntity(entity, Collections.singletonList(classification)); + } + } + } + private List<AtlasVertex> addTagPropagation(AtlasVertex classificationVertex, List<AtlasVertex> propagatedEntityVertices) { List<AtlasVertex> ret = null; @@ -1634,6 +1678,12 @@ public class EntityGraphMapper { AtlasClassificationType classificationType = typeRegistry.getClassificationTypeByName(classificationName); for (AtlasVertex propagatedEntityVertex : propagatedEntityVertices) { + AtlasEdge existingEdge = getPropagatedClassificationEdge(propagatedEntityVertex, classificationVertex); + + if (existingEdge != null) { + continue; + } + String entityTypeName = getTypeName(propagatedEntityVertex); AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entityTypeName); @@ -1651,7 +1701,7 @@ public class EntityGraphMapper { graphHelper.addClassificationEdge(propagatedEntityVertex, classificationVertex, true); - addListProperty(propagatedEntityVertex, PROPAGATED_TRAIT_NAMES_PROPERTY_KEY, classificationName); + addToPropagatedTraitNames(propagatedEntityVertex, classificationName); } } } @@ -1679,7 +1729,7 @@ public class EntityGraphMapper { // map all the attributes to this newly created AtlasVertex mapAttributes(classification, traitInstanceVertex, operation, context); - AtlasEdge ret = getClassificationEdge(parentInstanceVertex, getTypeName(traitInstanceVertex)); + AtlasEdge ret = getClassificationEdge(parentInstanceVertex, traitInstanceVertex); if (ret == null) { ret = graphHelper.addClassificationEdge(parentInstanceVertex, traitInstanceVertex, false); http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java index 8fe635a..59513f5 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphRetriever.java @@ -22,6 +22,7 @@ import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.model.TimeBoundary; import org.apache.atlas.model.instance.AtlasClassification; +import org.apache.atlas.model.instance.AtlasClassification.PropagationState; import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo; import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityExtInfo; @@ -36,7 +37,6 @@ import org.apache.atlas.model.typedef.AtlasRelationshipDef.PropagateTags; import org.apache.atlas.model.typedef.AtlasRelationshipEndDef; import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef; import org.apache.atlas.repository.Constants; -import org.apache.atlas.repository.RepositoryException; import org.apache.atlas.repository.graph.GraphHelper; import org.apache.atlas.repository.graphdb.AtlasEdge; import org.apache.atlas.repository.graphdb.AtlasEdgeDirection; @@ -69,22 +69,28 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static org.apache.atlas.model.instance.AtlasClassification.PropagationState.ACTIVE; +import static org.apache.atlas.model.instance.AtlasClassification.PropagationState.DELETED; import static org.apache.atlas.model.typedef.AtlasBaseTypeDef.*; import static org.apache.atlas.repository.Constants.*; import static org.apache.atlas.repository.graph.GraphHelper.EDGE_LABEL_PREFIX; -import static org.apache.atlas.repository.graph.GraphHelper.addListProperty; -import static org.apache.atlas.repository.graph.GraphHelper.edgeExists; +import static org.apache.atlas.repository.graph.GraphHelper.addToPropagatedTraitNames; import static org.apache.atlas.repository.graph.GraphHelper.getAdjacentEdgesByLabel; +import static org.apache.atlas.repository.graph.GraphHelper.getAllClassificationEdges; import static org.apache.atlas.repository.graph.GraphHelper.getAllTraitNames; import static org.apache.atlas.repository.graph.GraphHelper.getAssociatedEntityVertex; +import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdge; +import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdgeState; import static org.apache.atlas.repository.graph.GraphHelper.getGuid; import static org.apache.atlas.repository.graph.GraphHelper.getIncomingEdgesByLabel; import static org.apache.atlas.repository.graph.GraphHelper.getOutGoingEdgesByLabel; import static org.apache.atlas.repository.graph.GraphHelper.getPropagateTags; +import static org.apache.atlas.repository.graph.GraphHelper.getPropagatedClassificationEdge; import static org.apache.atlas.repository.graph.GraphHelper.getRelationshipGuid; import static org.apache.atlas.repository.graph.GraphHelper.getTypeName; +import static org.apache.atlas.repository.graph.GraphHelper.isPropagatedClassificationEdge; import static org.apache.atlas.repository.graph.GraphHelper.isPropagationEnabled; -import static org.apache.atlas.repository.graph.GraphHelper.removePropagatedTraitNameFromVertex; +import static org.apache.atlas.repository.graph.GraphHelper.removeFromPropagatedTraitNames; import static org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1.getIdFromVertex; import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection; import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.BOTH; @@ -446,7 +452,8 @@ public final class EntityGraphRetriever { public List<AtlasClassification> getAllClassifications(AtlasVertex entityVertex) throws AtlasBaseException { List<AtlasClassification> ret = new ArrayList<>(); - Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL).edges(); + Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL) + .has(CLASSIFICATION_EDGE_STATE_PROPERTY_KEY, ACTIVE.name()).edges(); if (edges != null) { Iterator<AtlasEdge> iterator = edges.iterator(); @@ -487,9 +494,26 @@ public final class EntityGraphRetriever { } private void mapClassifications(AtlasVertex entityVertex, AtlasEntity entity) throws AtlasBaseException { - final List<AtlasClassification> classifications = getAllClassifications(entityVertex); + List<AtlasEdge> edges = getAllClassificationEdges(entityVertex); - entity.setClassifications(classifications); + if (CollectionUtils.isNotEmpty(edges)) { + List<AtlasClassification> allClassifications = new ArrayList<>(); + List<AtlasClassification> propagationDisabledClassifications = new ArrayList<>(); + + for (AtlasEdge edge : edges) { + PropagationState edgeState = getClassificationEdgeState(edge); + AtlasVertex classificationVertex = edge.getInVertex(); + + if (edgeState == ACTIVE) { + allClassifications.add(toAtlasClassification(classificationVertex)); + } else if (edgeState == DELETED && isPropagatedClassificationEdge(edge)) { + propagationDisabledClassifications.add(toAtlasClassification(classificationVertex)); + } + } + + entity.setClassifications(allClassifications); + entity.setPropagationDisabledClassifications(propagationDisabledClassifications); + } } private Object mapVertexToAttribute(AtlasVertex entityVertex, AtlasAttribute attribute, AtlasEntityExtInfo entityExtInfo) throws AtlasBaseException { @@ -964,17 +988,17 @@ public final class EntityGraphRetriever { AtlasClassificationType classificationType = typeRegistry.getClassificationTypeByName(classificationName); for (AtlasVertex impactedEntityVertex : impactedEntityVertices) { - if (edgeExists(impactedEntityVertex, classificationVertex, classificationName)) { + if (getClassificationEdge(impactedEntityVertex, classificationVertex) != null) { if (LOG.isDebugEnabled()) { LOG.debug(" --> Classification edge already exists from [{}] --> [{}][{}] using edge label: [{}]", - getTypeName(impactedEntityVertex), getTypeName(classificationVertex), getTypeName(associatedEntityVertex), classificationName); + getTypeName(impactedEntityVertex), getTypeName(classificationVertex), getTypeName(associatedEntityVertex), classificationName); } continue; - } else if (edgeExists(impactedEntityVertex, classificationVertex, CLASSIFICATION_LABEL)) { + } else if (getPropagatedClassificationEdge(impactedEntityVertex, classificationVertex) != null) { if (LOG.isDebugEnabled()) { LOG.debug(" --> Propagated classification edge already exists from [{}] --> [{}][{}] using edge label: [{}]", - getTypeName(impactedEntityVertex), getTypeName(classificationVertex), getTypeName(associatedEntityVertex), CLASSIFICATION_LABEL); + getTypeName(impactedEntityVertex), getTypeName(classificationVertex), getTypeName(associatedEntityVertex), CLASSIFICATION_LABEL); } continue; @@ -997,9 +1021,15 @@ public final class EntityGraphRetriever { getTypeName(impactedEntityVertex), getTypeName(classificationVertex), getTypeName(associatedEntityVertex), CLASSIFICATION_LABEL); } + AtlasEdge existingEdge = getPropagatedClassificationEdge(impactedEntityVertex, classificationVertex); + + if (existingEdge != null) { + continue; + } + graphHelper.addClassificationEdge(impactedEntityVertex, classificationVertex, true); - addListProperty(impactedEntityVertex, PROPAGATED_TRAIT_NAMES_PROPERTY_KEY, classificationName); + addToPropagatedTraitNames(impactedEntityVertex, classificationName); } } } @@ -1035,20 +1065,18 @@ public final class EntityGraphRetriever { } // remove propagated classification edge and classificationName from propagatedTraitNames vertex property - if (edgeExists(impactedEntityVertex, classificationVertex, CLASSIFICATION_LABEL)) { - try { - if (LOG.isDebugEnabled()) { - LOG.debug(" --> Removing propagated classification edge from [{}] --> [{}][{}] with edge label: [{}]", - getTypeName(impactedEntityVertex), getTypeName(classificationVertex), getTypeName(associatedEntityVertex), CLASSIFICATION_LABEL); - } + AtlasEdge propagatedEdge = getPropagatedClassificationEdge(impactedEntityVertex, classificationVertex); - AtlasEdge propagatedEdge = graphHelper.getOrCreateEdge(impactedEntityVertex, classificationVertex, CLASSIFICATION_LABEL); + if (propagatedEdge != null) { + if (LOG.isDebugEnabled()) { + LOG.debug(" --> Removing propagated classification edge from [{}] --> [{}][{}] with edge label: [{}]", + getTypeName(impactedEntityVertex), getTypeName(classificationVertex), getTypeName(associatedEntityVertex), CLASSIFICATION_LABEL); + } - graphHelper.removeEdge(propagatedEdge); + graphHelper.removeEdge(propagatedEdge); - removePropagatedTraitNameFromVertex(impactedEntityVertex, classificationName); - } catch (RepositoryException e) { - throw new AtlasBaseException(AtlasErrorCode.INTERNAL_ERROR, e); + if (getClassificationEdgeState(propagatedEdge) == ACTIVE) { + removeFromPropagatedTraitNames(impactedEntityVertex, classificationName); } } else { if (LOG.isDebugEnabled()) { http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java b/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java index 9b4c91d..fa2332e 100644 --- a/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java +++ b/repository/src/test/java/org/apache/atlas/query/GremlinQueryComposerTest.java @@ -36,13 +36,13 @@ import static org.testng.Assert.fail; public class GremlinQueryComposerTest { @Test public void classification() { - String expected = "g.V().outE('classifiedAs').has('__name', within('PII')).outV().dedup().limit(25).toList()"; + String expected = "g.V().outE('classifiedAs').has('__name', within('PII')).has('__state', 'ACTIVE').outV().dedup().limit(25).toList()"; verify("PII", expected); } @Test() public void dimension() { - String expected = "g.V().has('__typeName', 'Table').outE('classifiedAs').has('__name', within('Dimension')).outV().dedup().limit(25).toList()"; + String expected = "g.V().has('__typeName', 'Table').outE('classifiedAs').has('__name', within('Dimension')).has('__state', 'ACTIVE').outV().dedup().limit(25).toList()"; verify("Table isa Dimension", expected); verify("Table is Dimension", expected); verify("Table where Table is Dimension", expected); @@ -295,14 +295,14 @@ public class GremlinQueryComposerTest { @Test public void keywordsInWhereClause() { verify("Table as t where t has name and t isa Dimension", - "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.outE('classifiedAs').has('__name', within('Dimension')).outV()).dedup().limit(25).toList()"); + "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.outE('classifiedAs').has('__name', within('Dimension')).has('__state', 'ACTIVE').outV()).dedup().limit(25).toList()"); verify("Table as t where t has name and t.name = 'sales_fact'", "g.V().has('__typeName', 'Table').as('t').and(__.has('Table.name'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); verify("Table as t where t is Dimension and t.name = 'sales_fact'", - "g.V().has('__typeName', 'Table').as('t').and(__.outE('classifiedAs').has('__name', within('Dimension')).outV(),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); - verify("Table isa 'Dimension' and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.outE('classifiedAs').has('__name', within('Dimension')).outV(),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); + "g.V().has('__typeName', 'Table').as('t').and(__.outE('classifiedAs').has('__name', within('Dimension')).has('__state', 'ACTIVE').outV(),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); + verify("Table isa 'Dimension' and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.outE('classifiedAs').has('__name', within('Dimension')).has('__state', 'ACTIVE').outV(),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); verify("Table has name and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('Table.name'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); - verify("Table is 'Dimension' and Table has owner and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.outE('classifiedAs').has('__name', within('Dimension')).outV(),__.has('Table.owner'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); + verify("Table is 'Dimension' and Table has owner and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.outE('classifiedAs').has('__name', within('Dimension')).has('__state', 'ACTIVE').outV(),__.has('Table.owner'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); verify("Table has name and Table has owner and name = 'sales_fact'", "g.V().has('__typeName', 'Table').and(__.has('Table.name'),__.has('Table.owner'),__.has('Table.name', eq('sales_fact'))).dedup().limit(25).toList()"); } http://git-wip-us.apache.org/repos/asf/atlas/blob/0f689faa/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java ---------------------------------------------------------------------- diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java index fdafa2c..17a6ece 100644 --- a/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java +++ b/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java @@ -475,6 +475,52 @@ public class EntityREST { } } + + /** + * Disable/Enable propagated classification for an existing entity represented by its guid. + * @param guid globally unique identifier for the entity + * @param classificationName name of the propagated classification + * @param sourceEntityGuid source entity guid of the propagated classification + * @param disablePropagation disable/enable propagation + */ + @PUT + @Path("/guid/{guid}/propagatedClassifications/{classificationName}") + @Produces(Servlets.JSON_MEDIA_TYPE) + public void setPropagatedClassificationState(@PathParam("guid") String guid, + @PathParam("classificationName") final String classificationName, + @QueryParam("sourceEntityGuid") String sourceEntityGuid, + @QueryParam("disablePropagation") boolean disablePropagation) throws AtlasBaseException { + Servlets.validateQueryParamLength("guid", guid); + Servlets.validateQueryParamLength("classificationName", classificationName); + Servlets.validateQueryParamLength("sourceEntityGuid", sourceEntityGuid); + + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityREST.setPropagatedClassificationState(" + guid + "," + classificationName + "," + sourceEntityGuid + "," + disablePropagation + ")"); + } + + if (StringUtils.isEmpty(guid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); + } + + if (StringUtils.isEmpty(classificationName)) { + throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "propagated classification not specified"); + } + + if (StringUtils.isEmpty(sourceEntityGuid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, sourceEntityGuid); + } + + ensureClassificationType(classificationName); + + entitiesStore.setPropagatedClassificationState(guid, classificationName, sourceEntityGuid, disablePropagation); + } finally { + AtlasPerfTracer.log(perf); + } + } + /******************************************************************/ /** Bulk API operations **/ /******************************************************************/
