Commit f59284ad by Sarath Subramanian

ATLAS-2040: Relationship with many-to-many cardinality gives incorrect relationship attribute value

parent 1b7e41f1
......@@ -31,6 +31,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection;
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;
......@@ -118,24 +119,33 @@ public class AtlasRelationshipType extends AtlasStructType {
}
private void addRelationshipEdgeDirection() {
AtlasRelationshipEndDef endDef1 = relationshipDef.getEndDef1();
AtlasRelationshipEndDef endDef2 = relationshipDef.getEndDef2();
AtlasAttribute end1Attribute = end1Type.getRelationshipAttribute(endDef1.getName());
AtlasAttribute end2Attribute = end2Type.getRelationshipAttribute(endDef2.getName());
AtlasRelationshipEndDef endDef1 = relationshipDef.getEndDef1();
AtlasRelationshipEndDef endDef2 = relationshipDef.getEndDef2();
//default relationship edge direction is end1 (out) -> end2 (in)
AtlasRelationshipEdgeDirection end1Direction = OUT;
AtlasRelationshipEdgeDirection end2Direction = IN;
if (StringUtils.equals(endDef1.getType(), endDef2.getType()) &&
StringUtils.equals(endDef1.getName(), endDef2.getName())) {
if (endDef1.getIsLegacyAttribute() && endDef2.getIsLegacyAttribute()) {
end2Direction = OUT;
} else if (!endDef1.getIsLegacyAttribute() && endDef2.getIsLegacyAttribute()) {
end1Direction = IN;
end2Direction = OUT;
}
AtlasAttribute endAttribute = end1Type.getRelationshipAttribute(endDef1.getName());
end1Attribute.setRelationshipEdgeDirection(end1Direction);
end2Attribute.setRelationshipEdgeDirection(end2Direction);
endAttribute.setRelationshipEdgeDirection(BOTH);
} else {
AtlasAttribute end1Attribute = end1Type.getRelationshipAttribute(endDef1.getName());
AtlasAttribute end2Attribute = end2Type.getRelationshipAttribute(endDef2.getName());
//default relationship edge direction is end1 (out) -> end2 (in)
AtlasRelationshipEdgeDirection end1Direction = OUT;
AtlasRelationshipEdgeDirection end2Direction = IN;
if (endDef1.getIsLegacyAttribute() && endDef2.getIsLegacyAttribute()) {
end2Direction = OUT;
} else if (!endDef1.getIsLegacyAttribute() && endDef2.getIsLegacyAttribute()) {
end1Direction = IN;
end2Direction = OUT;
}
end1Attribute.setRelationshipEdgeDirection(end1Direction);
end2Attribute.setRelationshipEdgeDirection(end2Direction);
}
}
@Override
......@@ -200,7 +210,6 @@ public class AtlasRelationshipType extends AtlasStructType {
AtlasRelationshipEndDef endDef2 = relationshipDef.getEndDef2();
RelationshipCategory relationshipCategory = relationshipDef.getRelationshipCategory();
String name = relationshipDef.getName();
boolean isContainer1 = endDef1.getIsContainer();
boolean isContainer2 = endDef2.getIsContainer();
......
......@@ -794,6 +794,6 @@ public class AtlasStructType extends AtlasType {
private static final char DOUBLE_QUOTE_CHAR = '"';
private static final char SPACE_CHAR = ' ';
public enum AtlasRelationshipEdgeDirection { IN, OUT }
public enum AtlasRelationshipEdgeDirection { IN, OUT, BOTH }
}
}
......@@ -23,8 +23,8 @@ import com.google.common.collect.ImmutableSet;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
import org.apache.atlas.model.typedef.AtlasClassificationDef;
import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.atlas.model.typedef.AtlasEnumDef;
......@@ -33,18 +33,17 @@ import org.apache.atlas.model.typedef.AtlasRelationshipDef;
import org.apache.atlas.model.typedef.AtlasRelationshipEndDef;
import org.apache.atlas.model.typedef.AtlasStructDef;
import org.apache.atlas.model.typedef.AtlasTypesDef;
import org.apache.atlas.type.AtlasTypeUtil;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import static org.apache.atlas.model.typedef.AtlasBaseTypeDef.getArrayTypeName;
import static org.apache.atlas.model.typedef.AtlasBaseTypeDef.getMapTypeName;
import static org.apache.atlas.model.typedef.AtlasRelationshipDef.PropagateTags.BOTH;
import static org.apache.atlas.model.typedef.AtlasRelationshipDef.PropagateTags.ONE_TO_TWO;
import static org.apache.atlas.model.typedef.AtlasRelationshipDef.RelationshipCategory.AGGREGATION;
import static org.apache.atlas.model.typedef.AtlasRelationshipDef.RelationshipCategory.ASSOCIATION;
......@@ -72,12 +71,13 @@ public final class TestRelationshipUtilsV2 {
public static final String EMPLOYEE_TYPE = "Employee";
public static final String EMPLOYEE_DEPARTMENT_TYPE = "EmployeeDepartment";
public static final String EMPLOYEE_MANAGER_TYPE = "EmployeeManager";
public static final String EMPLOYEE_MENTOR_TYPE = "EmployeeMentor";
public static final String EMPLOYEE_MENTORS_TYPE = "EmployeeMentors";
public static final String EMPLOYEE_FRIENDS_TYPE = "EmployeeFriends";
public static final String PERSON_SIBLING_TYPE = "PersonSibling";
public static final String TYPE_A = "A";
public static final String TYPE_B = "B";
public static final String DEFAULT_VERSION = "1.0";
private TestRelationshipUtilsV2() { }
public static AtlasTypesDef getDepartmentEmployeeTypes() throws AtlasBaseException {
......@@ -121,23 +121,36 @@ public final class TestRelationshipUtilsV2 {
DEFAULT_VERSION, AGGREGATION, ONE_TO_TWO,
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "department", SINGLE),
new AtlasRelationshipEndDef(DEPARTMENT_TYPE, "employees", SET, true));
/******* [Manager -> Employee] Relationship *******/
AtlasRelationshipDef employeeManagerType = new AtlasRelationshipDef(EMPLOYEE_MANAGER_TYPE, description(EMPLOYEE_MANAGER_TYPE),
DEFAULT_VERSION, AGGREGATION, ONE_TO_TWO,
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "manager", SINGLE),
new AtlasRelationshipEndDef(MANAGER_TYPE, "subordinates", SET, true));
/******* [Mentor -> Employee] Relationship *******/
AtlasRelationshipDef employeeMentorType = new AtlasRelationshipDef(EMPLOYEE_MENTOR_TYPE, description(EMPLOYEE_MENTOR_TYPE),
/******* [Mentors -> Employee] Relationship *******/
AtlasRelationshipDef employeeMentorsType = new AtlasRelationshipDef(EMPLOYEE_MENTORS_TYPE, description(EMPLOYEE_MENTORS_TYPE),
DEFAULT_VERSION, AGGREGATION, ONE_TO_TWO,
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "mentors", SET),
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "mentees", SET, true));
/******* [Friends -> Employee] Relationship *******/
AtlasRelationshipDef employeeFriendsType = new AtlasRelationshipDef(EMPLOYEE_FRIENDS_TYPE, description(EMPLOYEE_FRIENDS_TYPE),
DEFAULT_VERSION, ASSOCIATION, ONE_TO_TWO,
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "mentor", SINGLE),
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "mentees", SET));
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "friends", SET),
new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "friends", SET));
/******* [Person -> Sibling] Relationship *******/
AtlasRelationshipDef personSiblingType = new AtlasRelationshipDef(PERSON_SIBLING_TYPE, description(PERSON_SIBLING_TYPE),
DEFAULT_VERSION, ASSOCIATION, BOTH,
new AtlasRelationshipEndDef(PERSON_TYPE, "sibling", SINGLE),
new AtlasRelationshipEndDef(PERSON_TYPE, "sibling", SINGLE));
return new AtlasTypesDef(ImmutableList.of(orgLevelType),
ImmutableList.of(addressType),
ImmutableList.of(securityClearanceType),
ImmutableList.of(personType, employeeType, departmentType, managerType),
ImmutableList.of(employeeDepartmentType, employeeManagerType, employeeMentorType));
ImmutableList.of(employeeDepartmentType, employeeManagerType, employeeMentorsType, employeeFriendsType, personSiblingType));
}
public static AtlasEntitiesWithExtInfo getDepartmentEmployeeInstances() {
......@@ -163,25 +176,30 @@ public final class TestRelationshipUtilsV2 {
johnAddr.setAttribute("street", "Stewart Drive");
johnAddr.setAttribute("city", "Sunnyvale");
/******* Manager - Jane (John and Max subordinates) *******/
AtlasStruct mikeAddr = new AtlasStruct(ADDRESS_TYPE);
mikeAddr.setAttribute("street", "Casa Verde St");
mikeAddr.setAttribute("city", "San Jose");
/******* Manager - Jane (Subordinates: [John, Max]) *******/
AtlasEntity jane = new AtlasEntity(MANAGER_TYPE);
jane.setAttribute("name", "Jane");
jane.setRelationshipAttribute("department", getAtlasObjectId(hrDept));
jane.setAttribute("address", janeAddr);
/******* Manager - Julius (no subordinates) *******/
/******* Manager - Julius (Subordinates: [], Sibling: Jane) *******/
AtlasEntity julius = new AtlasEntity(MANAGER_TYPE);
julius.setAttribute("name", "Julius");
julius.setRelationshipAttribute("department", getAtlasObjectId(hrDept));
julius.setRelationshipAttribute("sibling", getAtlasObjectId(jane));
julius.setAttribute("address", juliusAddr);
/******* Employee - Max (Manager: Jane, Mentor: Julius) *******/
/******* Employee - Max (Manager: Jane, Mentors: [Julius], Sibling: Julius) *******/
AtlasEntity max = new AtlasEntity(EMPLOYEE_TYPE);
max.setAttribute("name", "Max");
max.setRelationshipAttribute("department", getAtlasObjectId(hrDept));
max.setAttribute("address", maxAddr);
max.setRelationshipAttribute("manager", getAtlasObjectId(jane));
max.setRelationshipAttribute("mentor", getAtlasObjectId(julius));
max.setRelationshipAttribute("mentors", getAtlasObjectIds(julius));
max.setAttribute("birthday",new Date(1979, 3, 15));
max.setAttribute("hasPets", true);
max.setAttribute("age", 36);
......@@ -193,13 +211,14 @@ public final class TestRelationshipUtilsV2 {
max.setAttribute("numberOfStarsEstimate", new BigInteger("1000000000000000000000000000000"));
max.setAttribute("approximationOfPi", new BigDecimal("3.1415926535897932"));
/******* Employee - John (Manager: Jane, Mentor: Max) *******/
/******* Employee - John (Manager: Jane, Mentors: [Max], Friends: [Max]) *******/
AtlasEntity john = new AtlasEntity(EMPLOYEE_TYPE);
john.setAttribute("name", "John");
john.setRelationshipAttribute("department", getAtlasObjectId(hrDept));
john.setAttribute("address", johnAddr);
john.setRelationshipAttribute("manager", getAtlasObjectId(jane));
john.setRelationshipAttribute("mentor", getAtlasObjectId(max));
john.setRelationshipAttribute("mentors", getAtlasObjectIds(max, julius));
john.setRelationshipAttribute("friends", getAtlasObjectIds(max));
john.setAttribute("birthday",new Date(1950, 5, 15));
john.setAttribute("hasPets", true);
john.setAttribute("numberOfCars", 1);
......@@ -211,11 +230,30 @@ public final class TestRelationshipUtilsV2 {
john.setAttribute("numberOfStarsEstimate", new BigInteger("1000000000000000000000"));
john.setAttribute("approximationOfPi", new BigDecimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286"));
/******* Employee - Mike (Manager: Julius, Friends: [Max, John]) *******/
AtlasEntity mike = new AtlasEntity(EMPLOYEE_TYPE);
mike.setAttribute("name", "Mike");
mike.setRelationshipAttribute("department", getAtlasObjectId(hrDept));
mike.setAttribute("address", mikeAddr);
mike.setRelationshipAttribute("manager", getAtlasObjectId(julius));
mike.setRelationshipAttribute("friends", getAtlasObjectIds(max, john));
mike.setAttribute("birthday",new Date(1947, 8, 15));
mike.setAttribute("hasPets", false);
mike.setAttribute("numberOfCars", 2);
mike.setAttribute("houseNumber", 3737);
mike.setAttribute("carMileage", 25000);
mike.setAttribute("shares", Long.MIN_VALUE);
mike.setAttribute("salary", Double.MIN_VALUE);
mike.setAttribute("age", 37);
mike.setAttribute("numberOfStarsEstimate", new BigInteger("5000050000050000050005"));
mike.setAttribute("approximationOfPi", new BigDecimal("3.14159"));
ret.addEntity(hrDept);
ret.addEntity(jane);
ret.addEntity(julius);
ret.addEntity(max);
ret.addEntity(john);
ret.addEntity(mike);
return ret;
}
......@@ -264,4 +302,16 @@ public final class TestRelationshipUtilsV2 {
private static ImmutableSet<String> superType(String superTypeName) {
return StringUtils.isNotEmpty(superTypeName) ? ImmutableSet.of(superTypeName) : ImmutableSet.<String>of();
}
private static List<AtlasObjectId> getAtlasObjectIds(AtlasEntity... entities) {
List<AtlasObjectId> ret = new ArrayList<>();
if (ArrayUtils.isNotEmpty(entities)) {
for (AtlasEntity entity : entities) {
ret.add(getAtlasObjectId(entity));
}
}
return ret;
}
}
\ No newline at end of file
......@@ -42,7 +42,6 @@ import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasRelationshipType;
import org.apache.atlas.type.AtlasStructType;
import org.apache.atlas.type.AtlasType;
import org.apache.atlas.typesystem.IReferenceableInstance;
import org.apache.atlas.typesystem.ITypedInstance;
......@@ -86,6 +85,10 @@ import java.util.Set;
import java.util.Stack;
import java.util.UUID;
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;
/**
* Utility class for graph operations.
*/
......@@ -308,7 +311,7 @@ public final class GraphHelper {
//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 Iterator<AtlasEdge> getAdjacentEdgesByLabel(AtlasVertex instanceVertex, AtlasEdgeDirection direction, final String edgeLabel) {
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);
}
......@@ -348,11 +351,11 @@ public final class GraphHelper {
return null;
}
public Iterator<AtlasEdge> getIncomingEdgesByLabel(AtlasVertex instanceVertex, String edgeLabel) {
public static Iterator<AtlasEdge> getIncomingEdgesByLabel(AtlasVertex instanceVertex, String edgeLabel) {
return getAdjacentEdgesByLabel(instanceVertex, AtlasEdgeDirection.IN, edgeLabel);
}
public Iterator<AtlasEdge> getOutGoingEdgesByLabel(AtlasVertex instanceVertex, String edgeLabel) {
public static Iterator<AtlasEdge> getOutGoingEdgesByLabel(AtlasVertex instanceVertex, String edgeLabel) {
return getAdjacentEdgesByLabel(instanceVertex, AtlasEdgeDirection.OUT, edgeLabel);
}
......@@ -361,20 +364,24 @@ public final class GraphHelper {
switch (edgeDirection) {
case IN:
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.IN);
break;
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.IN);
break;
case OUT:
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.OUT);
break;
case BOTH:
default:
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.OUT);
ret = getEdgeForLabel(vertex, edgeLabel, AtlasEdgeDirection.BOTH);
break;
}
return ret;
}
public Iterator<AtlasEdge> getEdgesForLabel(AtlasVertex vertex, String edgeLabel, AtlasRelationshipEdgeDirection edgeDirection) {
Iterator<AtlasEdge> ret;
public static Iterator<AtlasEdge> getEdgesForLabel(AtlasVertex vertex, String edgeLabel, AtlasRelationshipEdgeDirection edgeDirection) {
Iterator<AtlasEdge> ret = null;
switch (edgeDirection) {
case IN:
......@@ -382,8 +389,11 @@ public final class GraphHelper {
break;
case OUT:
default:
ret = getOutGoingEdgesByLabel(vertex, edgeLabel);
ret = getOutGoingEdgesByLabel(vertex, edgeLabel);
break;
case BOTH:
ret = getAdjacentEdgesByLabel(vertex, AtlasEdgeDirection.BOTH, edgeLabel);
break;
}
......@@ -1341,32 +1351,38 @@ public final class GraphHelper {
return StringUtils.isNotEmpty(edge.getLabel()) ? edgeLabel.startsWith("r:") : false;
}
public static AtlasObjectId getReferenceObjectId(AtlasEdge edge, AtlasRelationshipEdgeDirection relationshipDirection) {
public static AtlasObjectId getReferenceObjectId(AtlasEdge edge, AtlasRelationshipEdgeDirection relationshipDirection,
AtlasVertex parentVertex) {
AtlasObjectId ret = null;
if (relationshipDirection == AtlasRelationshipEdgeDirection.OUT) {
ret = new AtlasObjectId(getGuid(edge.getInVertex()), getTypeName(edge.getInVertex()));
if (relationshipDirection == OUT) {
ret = getAtlasObjectIdForInVertex(edge);
} else if (relationshipDirection == IN) {
ret = getAtlasObjectIdForOutVertex(edge);
} else if (relationshipDirection == AtlasRelationshipEdgeDirection.IN) {
ret = new AtlasObjectId(getGuid(edge.getOutVertex()), getTypeName(edge.getOutVertex()));
} 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 getCurrentObjectId(AtlasEdge edge, AtlasRelationshipEdgeDirection relationshipDirection) {
String typeName = null;
String guid = null;
if (relationshipDirection == AtlasRelationshipEdgeDirection.OUT) {
typeName = GraphHelper.getTypeName(edge.getOutVertex());
guid = GraphHelper.getGuid(edge.getOutVertex());
public static AtlasObjectId getAtlasObjectIdForOutVertex(AtlasEdge edge) {
return new AtlasObjectId(getGuid(edge.getOutVertex()), getTypeName(edge.getOutVertex()));
}
} else if (relationshipDirection == AtlasRelationshipEdgeDirection.IN) {
typeName = GraphHelper.getTypeName(edge.getInVertex());
guid = GraphHelper.getGuid(edge.getInVertex());
}
public static AtlasObjectId getAtlasObjectIdForInVertex(AtlasEdge edge) {
return new AtlasObjectId(getGuid(edge.getInVertex()), getTypeName(edge.getInVertex()));
}
return new AtlasObjectId(guid, typeName);
private static boolean verticesEquals(AtlasVertex vertexA, AtlasVertex vertexB) {
return StringUtils.equals(getGuid(vertexB), getGuid(vertexA));
}
}
\ No newline at end of file
......@@ -40,6 +40,7 @@ import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection;
import org.apache.atlas.type.AtlasType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -54,9 +55,13 @@ import java.util.Set;
import java.util.Stack;
import static org.apache.atlas.repository.graph.GraphHelper.EDGE_LABEL_PREFIX;
import static org.apache.atlas.repository.graph.GraphHelper.getAtlasObjectIdForInVertex;
import static org.apache.atlas.repository.graph.GraphHelper.getAtlasObjectIdForOutVertex;
import static org.apache.atlas.repository.graph.GraphHelper.getGuid;
import static org.apache.atlas.repository.graph.GraphHelper.getReferenceObjectId;
import static org.apache.atlas.repository.graph.GraphHelper.isRelationshipEdge;
import static org.apache.atlas.repository.graph.GraphHelper.string;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.BOTH;
public abstract class DeleteHandlerV1 {
......@@ -219,14 +224,14 @@ public abstract class DeleteHandlerV1 {
* @throws AtlasException
*/
public boolean deleteEdgeReference(AtlasEdge edge, TypeCategory typeCategory, boolean isOwned,
boolean forceDeleteStructTrait) throws AtlasBaseException {
boolean forceDeleteStructTrait, AtlasVertex vertex) throws AtlasBaseException {
// default edge direction is outward
return deleteEdgeReference(edge, typeCategory, isOwned, forceDeleteStructTrait, AtlasRelationshipEdgeDirection.OUT);
return deleteEdgeReference(edge, typeCategory, isOwned, forceDeleteStructTrait, AtlasRelationshipEdgeDirection.OUT, vertex);
}
public boolean deleteEdgeReference(AtlasEdge edge, TypeCategory typeCategory, boolean isOwned, boolean forceDeleteStructTrait,
AtlasRelationshipEdgeDirection relationshipDirection) throws AtlasBaseException {
AtlasRelationshipEdgeDirection relationshipDirection, AtlasVertex entityVertex) throws AtlasBaseException {
LOG.debug("Deleting {}", string(edge));
boolean forceDelete =
(typeCategory == TypeCategory.STRUCT || typeCategory == TypeCategory.CLASSIFICATION) && forceDeleteStructTrait;
......@@ -250,7 +255,7 @@ public abstract class DeleteHandlerV1 {
if (isRelationshipEdge(edge)) {
deleteEdge(edge, false);
AtlasObjectId deletedReferenceObjectId = getReferenceObjectId(edge, relationshipDirection);
AtlasObjectId deletedReferenceObjectId = getReferenceObjectId(edge, relationshipDirection, entityVertex);
RequestContextV1.get().recordEntityUpdate(deletedReferenceObjectId);
} else {
//legacy case - not a relationship edge
......@@ -344,7 +349,7 @@ public abstract class DeleteHandlerV1 {
if (edges != null) {
while (edges.hasNext()) {
AtlasEdge edge = edges.next();
deleteEdgeReference(edge, elemType.getTypeCategory(), isOwned, false);
deleteEdgeReference(edge, elemType.getTypeCategory(), isOwned, false, instanceVertex);
}
}
}
......@@ -377,7 +382,7 @@ public abstract class DeleteHandlerV1 {
boolean isOwned) throws AtlasBaseException {
AtlasEdge edge = graphHelper.getEdgeForLabel(outVertex, edgeLabel);
if (edge != null) {
deleteEdgeReference(edge, typeCategory, isOwned, false);
deleteEdgeReference(edge, typeCategory, isOwned, false, outVertex);
}
}
......
......@@ -51,6 +51,7 @@ import org.apache.atlas.type.AtlasType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.type.AtlasTypeUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
......@@ -70,7 +71,9 @@ import static org.apache.atlas.repository.graph.GraphHelper.getTypeName;
import static org.apache.atlas.repository.graph.GraphHelper.isRelationshipEdge;
import static org.apache.atlas.repository.graph.GraphHelper.string;
import static org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1.getIdFromVertex;
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;
@Component
public class EntityGraphMapper {
......@@ -353,7 +356,7 @@ public class EntityGraphMapper {
AtlasEdge newEdge = mapStructValue(ctx, context);
if (currentEdge != null && !currentEdge.equals(newEdge)) {
deleteHandler.deleteEdgeReference(currentEdge, ctx.getAttrType().getTypeCategory(), false, true);
deleteHandler.deleteEdgeReference(currentEdge, ctx.getAttrType().getTypeCategory(), false, true, ctx.getReferringVertex());
}
return newEdge;
......@@ -423,7 +426,7 @@ public class EntityGraphMapper {
//delete old reference
deleteHandler.deleteEdgeReference(currentEdge, ctx.getAttrType().getTypeCategory(), ctx.getAttribute().isOwnedRef(),
true, ctx.getAttribute().getRelationshipEdgeDirection());
true, ctx.getAttribute().getRelationshipEdgeDirection(), ctx.getReferringVertex());
}
return newEdge;
......@@ -457,7 +460,7 @@ public class EntityGraphMapper {
if (!inverseEdge.equals(newEdge)) {
// Disconnect old reference
deleteHandler.deleteEdgeReference(inverseEdge, inverseAttribute.getAttributeType().getTypeCategory(),
inverseAttribute.isOwnedRef(), true);
inverseAttribute.isOwnedRef(), true, inverseVertex);
}
else {
// Edge already exists for this attribute between these vertices.
......@@ -675,9 +678,7 @@ public class EntityGraphMapper {
Map<String, Object> relationshipAttributes = getRelationshipAttributes(ctx.getValue());
if (ctx.getCurrentEdge() != null) {
ret = updateRelationship(ctx.getCurrentEdge(), attributeVertex, edgeDirection, relationshipAttributes);
recordEntityUpdate(attributeVertex);
ret = updateRelationship(ctx.getCurrentEdge(), entityVertex, attributeVertex, edgeDirection, relationshipAttributes);
} else {
String relationshipName = graphHelper.getRelationshipDefName(entityVertex, entityType, attributeName);
......@@ -805,10 +806,16 @@ public class EntityGraphMapper {
List newElements = (List) ctx.getValue();
AtlasArrayType arrType = (AtlasArrayType) attribute.getAttributeType();
AtlasType elementType = arrType.getElementType();
List<Object> currentElements = getArrayElementsProperty(elementType, ctx.getReferringVertex(), ctx.getVertexProperty());
boolean isReference = AtlasGraphUtilsV1.isReference(elementType);
AtlasAttribute inverseRefAttribute = attribute.getInverseRefAttribute();
List<Object> newElementsCreated = new ArrayList<>();
List<Object> currentElements;
if (isRelationshipAttribute(attribute)) {
currentElements = getArrayElementsUsingRelationship(ctx.getReferringVertex(), attribute, elementType);
} else {
currentElements = getArrayElementsProperty(elementType, ctx.getReferringVertex(), ctx.getVertexProperty());
}
if (CollectionUtils.isNotEmpty(newElements)) {
for (int index = 0; index < newElements.size(); index++) {
......@@ -817,6 +824,7 @@ public class EntityGraphMapper {
ctx.getVertexProperty(), elementType, existingEdge);
Object newEntry = mapCollectionElementsToVertex(arrCtx, context);
if (isReference && newEntry instanceof AtlasEdge && inverseRefAttribute != null) {
// Update the inverse reference value.
AtlasEdge newEdge = (AtlasEdge) newEntry;
......@@ -829,7 +837,7 @@ public class EntityGraphMapper {
}
if (isReference) {
List<AtlasEdge> additionalEdges = removeUnusedArrayEntries(attribute, (List) currentElements, (List) newElementsCreated);
List<AtlasEdge> additionalEdges = removeUnusedArrayEntries(attribute, (List) currentElements, (List) newElementsCreated, ctx.getReferringVertex());
newElementsCreated.addAll(additionalEdges);
}
......@@ -1048,7 +1056,7 @@ public class EntityGraphMapper {
AtlasEdge currentEdge = (AtlasEdge)currentMap.get(currentKey);
if (!newMap.values().contains(currentEdge)) {
boolean deleted = deleteHandler.deleteEdgeReference(currentEdge, mapType.getValueType().getTypeCategory(), attribute.isOwnedRef(), true);
boolean deleted = deleteHandler.deleteEdgeReference(currentEdge, mapType.getValueType().getTypeCategory(), attribute.isOwnedRef(), true, vertex);
if (!deleted) {
additionalMap.put(currentKey, currentEdge);
......@@ -1104,8 +1112,10 @@ public class EntityGraphMapper {
return newEdge;
}
private AtlasEdge updateRelationship(AtlasEdge currentEdge, final AtlasVertex newEntityVertex, AtlasRelationshipEdgeDirection edgeDirection,
Map<String, Object> relationshipAttributes) throws AtlasBaseException {
private AtlasEdge updateRelationship(AtlasEdge currentEdge, final AtlasVertex parentEntityVertex, final AtlasVertex newEntityVertex,
AtlasRelationshipEdgeDirection edgeDirection, Map<String, Object> relationshipAttributes)
throws AtlasBaseException {
if (LOG.isDebugEnabled()) {
LOG.debug("Updating entity reference using relationship {} for reference attribute {}", getTypeName(newEntityVertex));
}
......@@ -1115,8 +1125,15 @@ public class EntityGraphMapper {
// Max's mentor updated from John to Jane (John.mentee --> Max.mentor)
// mentor attribute (IN direction), current mentee vertex (John) (OUT vertex)
String currentEntityId = (edgeDirection == IN) ? getIdFromVertex(currentEdge.getOutVertex()) :
getIdFromVertex(currentEdge.getInVertex());
String currentEntityId;
if (edgeDirection == IN) {
currentEntityId = getIdFromOutVertex(currentEdge);
} else if (edgeDirection == OUT) {
currentEntityId = getIdFromInVertex(currentEdge);
} else {
currentEntityId = getIdFromBothVertex(currentEdge, parentEntityVertex);
}
String newEntityId = getIdFromVertex(newEntityVertex);
AtlasEdge ret = currentEdge;
......@@ -1129,8 +1146,17 @@ public class EntityGraphMapper {
relationshipName = currentEdge.getLabel();
}
ret = (edgeDirection == IN) ? getOrCreateRelationship(newEntityVertex, currentEdge.getInVertex(), relationshipName, relationshipAttributes) :
getOrCreateRelationship(currentEdge.getOutVertex(), newEntityVertex, relationshipName, relationshipAttributes);
if (edgeDirection == IN) {
ret = getOrCreateRelationship(newEntityVertex, currentEdge.getInVertex(), relationshipName, relationshipAttributes);
} else if (edgeDirection == OUT) {
ret = getOrCreateRelationship(currentEdge.getOutVertex(), newEntityVertex, relationshipName, relationshipAttributes);
} else {
ret = getOrCreateRelationship(newEntityVertex, parentEntityVertex, relationshipName, relationshipAttributes);
}
//record entity update on new relationship vertex
recordEntityUpdate(newEntityVertex);
}
return ret;
......@@ -1145,6 +1171,21 @@ public class EntityGraphMapper {
}
}
public static List<Object> getArrayElementsUsingRelationship(AtlasVertex vertex, AtlasAttribute attribute, AtlasType elementType) {
List<Object> ret = null;
if (AtlasGraphUtilsV1.isReference(elementType)) {
AtlasRelationshipEdgeDirection edgeDirection = attribute.getRelationshipEdgeDirection();
String edgeLabel = attribute.getRelationshipEdgeLabel();
Iterator<AtlasEdge> edgesForLabel = GraphHelper.getEdgesForLabel(vertex, edgeLabel, edgeDirection);
ret = IteratorUtils.toList(edgesForLabel);
}
return ret;
}
private AtlasEdge getEdgeAt(List<Object> currentElements, int index, AtlasType elemType) {
AtlasEdge ret = null;
......@@ -1158,7 +1199,8 @@ public class EntityGraphMapper {
}
//Removes unused edges from the old collection, compared to the new collection
private List<AtlasEdge> removeUnusedArrayEntries(AtlasAttribute attribute, List<AtlasEdge> currentEntries, List<AtlasEdge> newEntries) throws AtlasBaseException {
private List<AtlasEdge> removeUnusedArrayEntries(AtlasAttribute attribute, List<AtlasEdge> currentEntries, List<AtlasEdge> newEntries, AtlasVertex entityVertex) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(currentEntries)) {
AtlasType entryType = ((AtlasArrayType) attribute.getAttributeType()).getElementType();
......@@ -1170,7 +1212,7 @@ public class EntityGraphMapper {
for (AtlasEdge edge : edgesToRemove) {
boolean deleted = deleteHandler.deleteEdgeReference(edge, entryType.getTypeCategory(), attribute.isOwnedRef(),
true, attribute.getRelationshipEdgeDirection());
true, attribute.getRelationshipEdgeDirection(), entityVertex);
if (!deleted) {
additionalElements.add(edge);
......@@ -1184,7 +1226,6 @@ public class EntityGraphMapper {
return Collections.emptyList();
}
private void setArrayElementsProperty(AtlasType elementType, AtlasVertex vertex, String vertexPropertyName, List<Object> values) {
if (AtlasGraphUtilsV1.isReference(elementType)) {
GraphHelper.setListPropertyFromElementIds(vertex, vertexPropertyName, (List) values);
......@@ -1334,7 +1375,7 @@ public class EntityGraphMapper {
String relationshipLabel = GraphHelper.getTraitLabel(entityTypeName, classificationName);
AtlasEdge edge = graphHelper.getEdgeForLabel(instanceVertex, relationshipLabel);
if (edge != null) {
deleteHandler.deleteEdgeReference(edge, TypeCategory.CLASSIFICATION, false, true);
deleteHandler.deleteEdgeReference(edge, TypeCategory.CLASSIFICATION, false, true, instanceVertex);
// update the traits in entity once trait removal is successful
traitNames.remove(classificationName);
......@@ -1433,7 +1474,7 @@ public class EntityGraphMapper {
private static void compactAttributes(AtlasEntity entity) {
if (entity != null) {
Map<String, Object> relationshipAttributes = entity.getRelationshipAttributes();
Map<String, Object> attributes = entity.getAttributes();
Map<String, Object> attributes = entity.getAttributes();
if (MapUtils.isNotEmpty(relationshipAttributes) && MapUtils.isNotEmpty(attributes)) {
for (String attrName : relationshipAttributes.keySet()) {
......@@ -1444,4 +1485,23 @@ public class EntityGraphMapper {
}
}
}
}
private String getIdFromInVertex(AtlasEdge edge) {
return getIdFromVertex(edge.getInVertex());
}
private String getIdFromOutVertex(AtlasEdge edge) {
return getIdFromVertex(edge.getOutVertex());
}
private String getIdFromBothVertex(AtlasEdge currentEdge, AtlasVertex parentEntityVertex) {
String parentEntityId = getIdFromVertex(parentEntityVertex);
String currentEntityId = getIdFromVertex(currentEdge.getInVertex());
if (StringUtils.equals(currentEntityId, parentEntityId)) {
currentEntityId = getIdFromOutVertex(currentEdge);
}
return currentEntityId;
}
}
\ No newline at end of file
......@@ -72,6 +72,9 @@ import static org.apache.atlas.model.typedef.AtlasBaseTypeDef.ATLAS_TYPE_STRING;
import static org.apache.atlas.repository.graph.GraphHelper.EDGE_LABEL_PREFIX;
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;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.IN;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.OUT;
public final class EntityGraphRetriever {
......@@ -683,10 +686,12 @@ public final class EntityGraphRetriever {
List<AtlasRelatedObjectId> ret = new ArrayList<>();
Iterator<AtlasEdge> edges = null;
if (attribute.getRelationshipEdgeDirection() == AtlasRelationshipEdgeDirection.IN) {
if (attribute.getRelationshipEdgeDirection() == IN) {
edges = graphHelper.getIncomingEdgesByLabel(entityVertex, attribute.getRelationshipEdgeLabel());
} else if (attribute.getRelationshipEdgeDirection() == AtlasRelationshipEdgeDirection.OUT) {
} else if (attribute.getRelationshipEdgeDirection() == OUT) {
edges = graphHelper.getOutGoingEdgesByLabel(entityVertex, attribute.getRelationshipEdgeLabel());
} else if (attribute.getRelationshipEdgeDirection() == BOTH) {
edges = graphHelper.getAdjacentEdgesByLabel(entityVertex, AtlasEdgeDirection.BOTH, attribute.getRelationshipEdgeLabel());
}
if (edges != null) {
......
......@@ -20,9 +20,15 @@ package org.apache.atlas.repository.store.graph.v1;
import com.google.common.collect.ImmutableList;
import org.apache.atlas.TestModules;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.testng.annotations.Guice;
import java.util.List;
import static org.apache.atlas.type.AtlasTypeUtil.getAtlasObjectId;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
/**
* Inverse reference update test with {@link HardDeleteHandlerV1}
......@@ -51,4 +57,56 @@ public class AtlasRelationshipStoreHardDeleteV1Test extends AtlasRelationshipSto
protected void verifyRelationshipAttributeUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b) {
verifyRelationshipAttributeValue(a1, "b", null);
}
}
@Override
protected void verifyRelationshipAttributeUpdate_ManyToMany_Friends(AtlasEntity max, AtlasEntity julius, AtlasEntity mike, AtlasEntity john) throws Exception {
AtlasObjectId johnId = employeeNameIdMap.get("John");
AtlasObjectId mikeId = employeeNameIdMap.get("Mike");
AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
AtlasObjectId maxId = employeeNameIdMap.get("Max");
List<AtlasObjectId> maxFriendsIds = toAtlasObjectIds(max.getRelationshipAttribute("friends"));
assertNotNull(maxFriendsIds);
assertEquals(maxFriendsIds.size(), 2);
assertObjectIdsContains(maxFriendsIds, johnId);
assertObjectIdsContains(maxFriendsIds, juliusId);
// Julius's updated friends: [Max]
List<AtlasObjectId> juliusFriendsIds = toAtlasObjectIds(julius.getRelationshipAttribute("friends"));
assertNotNull(juliusFriendsIds);
assertEquals(juliusFriendsIds.size(), 1);
assertObjectIdsContains(juliusFriendsIds, maxId);
// Mike's updated friends: [John]
List<AtlasObjectId> mikeFriendsIds = toAtlasObjectIds(mike.getRelationshipAttribute("friends"));
assertNotNull(mikeFriendsIds);
assertEquals(mikeFriendsIds.size(), 1);
assertObjectIdsContains(mikeFriendsIds, johnId);
// John's updated friends: [Max, Mike]
List<AtlasObjectId> johnFriendsIds = toAtlasObjectIds(john.getRelationshipAttribute("friends"));
assertNotNull(johnFriendsIds);
assertEquals(johnFriendsIds.size(), 2);
assertObjectIdsContains(johnFriendsIds, maxId);
assertObjectIdsContains(johnFriendsIds, mikeId);
}
protected void verifyRelationshipAttributeUpdate_OneToOne_Sibling(AtlasEntity julius, AtlasEntity jane, AtlasEntity mike) throws Exception {
AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
AtlasObjectId mikeId = employeeNameIdMap.get("Mike");
// Julius sibling updated to Mike
AtlasObjectId juliusSiblingId = toAtlasObjectId(julius.getRelationshipAttribute("sibling"));
assertNotNull(juliusSiblingId);
assertObjectIdEquals(juliusSiblingId, mikeId);
// Mike's sibling is Julius
AtlasObjectId mikeSiblingId = toAtlasObjectId(mike.getRelationshipAttribute("sibling"));
assertNotNull(mikeSiblingId);
assertObjectIdEquals(mikeSiblingId, juliusId);
// Julius removed from Jane's sibling (hard delete)
AtlasObjectId janeSiblingId = toAtlasObjectId(jane.getRelationshipAttribute("sibling"));
assertNull(janeSiblingId);
}
}
\ No newline at end of file
......@@ -20,9 +20,14 @@ package org.apache.atlas.repository.store.graph.v1;
import com.google.common.collect.ImmutableList;
import org.apache.atlas.TestModules;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.testng.annotations.Guice;
import java.util.List;
import static org.apache.atlas.type.AtlasTypeUtil.getAtlasObjectId;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
/**
......@@ -52,4 +57,60 @@ public class AtlasRelationshipStoreSoftDeleteV1Test extends AtlasRelationshipSto
protected void verifyRelationshipAttributeUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b) {
verifyRelationshipAttributeValue(a1, "b", b.getGuid());
}
}
@Override
protected void verifyRelationshipAttributeUpdate_ManyToMany_Friends(AtlasEntity max, AtlasEntity julius, AtlasEntity mike, AtlasEntity john) throws Exception {
AtlasObjectId johnId = employeeNameIdMap.get("John");
AtlasObjectId mikeId = employeeNameIdMap.get("Mike");
AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
AtlasObjectId maxId = employeeNameIdMap.get("Max");
// Max's updated friends: [Julius, John, Mike(soft deleted)]
List<AtlasObjectId> maxFriendsIds = toAtlasObjectIds(max.getRelationshipAttribute("friends"));
assertNotNull(maxFriendsIds);
assertEquals(maxFriendsIds.size(), 3);
assertObjectIdsContains(maxFriendsIds, johnId);
assertObjectIdsContains(maxFriendsIds, juliusId);
assertObjectIdsContains(maxFriendsIds, mikeId);
// Julius's updated friends: [Max]
List<AtlasObjectId> juliusFriendsIds = toAtlasObjectIds(julius.getRelationshipAttribute("friends"));
assertNotNull(juliusFriendsIds);
assertEquals(juliusFriendsIds.size(), 1);
assertObjectIdsContains(juliusFriendsIds, maxId);
// Mike's updated friends: [John, Max(soft deleted)]
List<AtlasObjectId> mikeFriendsIds = toAtlasObjectIds(mike.getRelationshipAttribute("friends"));
assertNotNull(mikeFriendsIds);
assertEquals(mikeFriendsIds.size(), 2);
assertObjectIdsContains(mikeFriendsIds, johnId);
assertObjectIdsContains(mikeFriendsIds, maxId);
// John's updated friends: [Max, Mike]
List<AtlasObjectId> johnFriendsIds = toAtlasObjectIds(john.getRelationshipAttribute("friends"));
assertNotNull(johnFriendsIds);
assertEquals(johnFriendsIds.size(), 2);
assertObjectIdsContains(johnFriendsIds, maxId);
assertObjectIdsContains(johnFriendsIds, mikeId);
}
protected void verifyRelationshipAttributeUpdate_OneToOne_Sibling(AtlasEntity julius, AtlasEntity jane, AtlasEntity mike) throws Exception {
AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
AtlasObjectId mikeId = employeeNameIdMap.get("Mike");
// Julius sibling updated to Mike
AtlasObjectId juliusSiblingId = toAtlasObjectId(julius.getRelationshipAttribute("sibling"));
assertNotNull(juliusSiblingId);
assertObjectIdEquals(juliusSiblingId, mikeId);
// Mike's sibling is Julius
AtlasObjectId mikeSiblingId = toAtlasObjectId(mike.getRelationshipAttribute("sibling"));
assertNotNull(mikeSiblingId);
assertObjectIdEquals(mikeSiblingId, juliusId);
// Jane's sibling is still Julius (soft delete)
AtlasObjectId janeSiblingId = toAtlasObjectId(jane.getRelationshipAttribute("sibling"));
assertNotNull(janeSiblingId);
assertObjectIdEquals(janeSiblingId, juliusId);
}
}
\ No newline at end of file
......@@ -131,21 +131,24 @@ public abstract class AtlasRelationshipStoreV1Test {
AtlasObjectId johnId = employeeNameIdMap.get("John");
AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
AtlasObjectId janeId = employeeNameIdMap.get("Jane");
AtlasObjectId mikeId = employeeNameIdMap.get("Mike");
AtlasEntity hrDept = getEntityFromStore(hrId.getGuid());
AtlasEntity max = getEntityFromStore(maxId.getGuid());
AtlasEntity john = getEntityFromStore(johnId.getGuid());
AtlasEntity julius = getEntityFromStore(juliusId.getGuid());
AtlasEntity jane = getEntityFromStore(janeId.getGuid());
AtlasEntity mike = getEntityFromStore(mikeId.getGuid());
// Department relationship attributes
List<AtlasObjectId> deptEmployees = toAtlasObjectIds(hrDept.getRelationshipAttribute("employees"));
assertNotNull(deptEmployees);
assertEquals(deptEmployees.size(), 4);
assertEquals(deptEmployees.size(), 5);
assertObjectIdsContains(deptEmployees, maxId);
assertObjectIdsContains(deptEmployees, johnId);
assertObjectIdsContains(deptEmployees, juliusId);
assertObjectIdsContains(deptEmployees, janeId);
assertObjectIdsContains(deptEmployees, mikeId);
// Max employee validation
AtlasObjectId maxDepartmentId = toAtlasObjectId(max.getRelationshipAttribute("department"));
......@@ -156,15 +159,22 @@ public abstract class AtlasRelationshipStoreV1Test {
assertNotNull(maxManagerId);
assertObjectIdEquals(maxManagerId, janeId);
AtlasObjectId maxMentorId = toAtlasObjectId(max.getRelationshipAttribute("mentor"));
assertNotNull(maxMentorId);
assertObjectIdEquals(maxMentorId, juliusId);
List<AtlasObjectId> maxMentorsId = toAtlasObjectIds(max.getRelationshipAttribute("mentors"));
assertNotNull(maxMentorsId);
assertEquals(maxMentorsId.size(), 1);
assertObjectIdEquals(maxMentorsId.get(0), juliusId);
List<AtlasObjectId> maxMenteesId = toAtlasObjectIds(max.getRelationshipAttribute("mentees"));
assertNotNull(maxMenteesId);
assertEquals(maxMenteesId.size(), 1);
assertObjectIdEquals(maxMenteesId.get(0), johnId);
List<AtlasObjectId> maxFriendsIds = toAtlasObjectIds(max.getRelationshipAttribute("friends"));
assertNotNull(maxFriendsIds);
assertEquals(maxFriendsIds.size(), 2);
assertObjectIdsContains(maxFriendsIds, mikeId);
assertObjectIdsContains(maxFriendsIds, johnId);
// John Employee validation
AtlasObjectId johnDepartmentId = toAtlasObjectId(john.getRelationshipAttribute("department"));
assertNotNull(johnDepartmentId);
......@@ -174,13 +184,42 @@ public abstract class AtlasRelationshipStoreV1Test {
assertNotNull(johnManagerId);
assertObjectIdEquals(johnManagerId, janeId);
AtlasObjectId johnMentorId = toAtlasObjectId(john.getRelationshipAttribute("mentor"));
assertNotNull(johnMentorId);
assertObjectIdEquals(johnMentorId, maxId);
List<AtlasObjectId> johnMentorIds = toAtlasObjectIds(john.getRelationshipAttribute("mentors"));
assertNotNull(johnMentorIds);
assertEquals(johnMentorIds.size(), 2);
assertObjectIdsContains(johnMentorIds, maxId);
assertObjectIdsContains(johnMentorIds, juliusId);
List<AtlasObjectId> johnMenteesId = toAtlasObjectIds(john.getRelationshipAttribute("mentees"));
assertEmpty(johnMenteesId);
List<AtlasObjectId> johnFriendsIds = toAtlasObjectIds(john.getRelationshipAttribute("friends"));
assertNotNull(johnFriendsIds);
assertEquals(johnFriendsIds.size(), 2);
assertObjectIdsContains(johnFriendsIds, mikeId);
assertObjectIdsContains(johnFriendsIds, maxId);
// Mike Employee validation
AtlasObjectId mikeDepartmentId = toAtlasObjectId(mike.getRelationshipAttribute("department"));
assertNotNull(mikeDepartmentId);
assertObjectIdEquals(mikeDepartmentId, hrId);
AtlasObjectId mikeManagerId = toAtlasObjectId(mike.getRelationshipAttribute("manager"));
assertNotNull(mikeManagerId);
assertObjectIdEquals(mikeManagerId, juliusId);
List<AtlasObjectId> mikeMentorIds = toAtlasObjectIds(mike.getRelationshipAttribute("mentors"));
assertEmpty(mikeMentorIds);
List<AtlasObjectId> mikeMenteesId = toAtlasObjectIds(mike.getRelationshipAttribute("mentees"));
assertEmpty(mikeMenteesId);
List<AtlasObjectId> mikeFriendsIds = toAtlasObjectIds(mike.getRelationshipAttribute("friends"));
assertNotNull(mikeFriendsIds);
assertEquals(mikeFriendsIds.size(), 2);
assertObjectIdsContains(mikeFriendsIds, maxId);
assertObjectIdsContains(mikeFriendsIds, johnId);
// Jane Manager validation
AtlasObjectId janeDepartmentId = toAtlasObjectId(jane.getRelationshipAttribute("department"));
assertNotNull(janeDepartmentId);
......@@ -189,8 +228,8 @@ public abstract class AtlasRelationshipStoreV1Test {
AtlasObjectId janeManagerId = toAtlasObjectId(jane.getRelationshipAttribute("manager"));
assertNull(janeManagerId);
AtlasObjectId janeMentorId = toAtlasObjectId(jane.getRelationshipAttribute("mentor"));
assertNull(janeMentorId);
List<AtlasObjectId> janeMentorIds = toAtlasObjectIds(jane.getRelationshipAttribute("mentors"));
assertEmpty(janeMentorIds);
List<AtlasObjectId> janeMenteesId = toAtlasObjectIds(jane.getRelationshipAttribute("mentees"));
assertEmpty(janeMenteesId);
......@@ -201,6 +240,13 @@ public abstract class AtlasRelationshipStoreV1Test {
assertObjectIdsContains(janeSubordinateIds, maxId);
assertObjectIdsContains(janeSubordinateIds, johnId);
List<AtlasObjectId> janeFriendsIds = toAtlasObjectIds(jane.getRelationshipAttribute("friends"));
assertEmpty(janeFriendsIds);
AtlasObjectId janeSiblingId = toAtlasObjectId(jane.getRelationshipAttribute("sibling"));
assertNotNull(janeSiblingId);
assertObjectIdEquals(janeSiblingId, juliusId);
// Julius Manager validation
AtlasObjectId juliusDepartmentId = toAtlasObjectId(julius.getRelationshipAttribute("department"));
assertNotNull(juliusDepartmentId);
......@@ -209,16 +255,26 @@ public abstract class AtlasRelationshipStoreV1Test {
AtlasObjectId juliusManagerId = toAtlasObjectId(julius.getRelationshipAttribute("manager"));
assertNull(juliusManagerId);
AtlasObjectId juliusMentorId = toAtlasObjectId(julius.getRelationshipAttribute("mentor"));
assertNull(juliusMentorId);
List<AtlasObjectId> juliusMentorIds = toAtlasObjectIds(julius.getRelationshipAttribute("mentors"));
assertEmpty(juliusMentorIds);
List<AtlasObjectId> juliusMenteesId = toAtlasObjectIds(julius.getRelationshipAttribute("mentees"));
assertNotNull(juliusMenteesId);
assertEquals(juliusMenteesId.size(), 1);
assertEquals(juliusMenteesId.size(), 2);
assertObjectIdsContains(juliusMenteesId, maxId);
assertObjectIdsContains(juliusMenteesId, johnId);
List<AtlasObjectId> juliusSubordinateIds = toAtlasObjectIds(julius.getRelationshipAttribute("subordinates"));
assertEmpty(juliusSubordinateIds);
assertNotNull(juliusSubordinateIds);
assertEquals(juliusSubordinateIds.size(), 1);
assertObjectIdsContains(juliusSubordinateIds, mikeId);
List<AtlasObjectId> juliusFriendsIds = toAtlasObjectIds(julius.getRelationshipAttribute("friends"));
assertEmpty(juliusFriendsIds);
AtlasObjectId juliusSiblingId = toAtlasObjectId(julius.getRelationshipAttribute("sibling"));
assertNotNull(juliusSiblingId);
assertObjectIdEquals(juliusSiblingId, janeId);
}
@Test
......@@ -226,6 +282,8 @@ public abstract class AtlasRelationshipStoreV1Test {
AtlasObjectId maxId = employeeNameIdMap.get("Max");
AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
AtlasObjectId janeId = employeeNameIdMap.get("Jane");
AtlasObjectId mikeId = employeeNameIdMap.get("Mike");
AtlasObjectId johnId = employeeNameIdMap.get("John");
// Change Max's Employee.manager reference to Julius and apply the change as a partial update.
// This should also update Julius to add Max to the inverse Manager.subordinates reference.
......@@ -249,9 +307,9 @@ public abstract class AtlasRelationshipStoreV1Test {
AtlasEntity maxEntity = updatedEntities.getEntity(maxId.getGuid());
verifyRelationshipAttributeValue(maxEntity, "manager", juliusId.getGuid());
// Max added to the subordinate list of Julius
// Max added to the subordinate list of Julius, existing subordinate is Mike
AtlasEntity juliusEntity = updatedEntities.getEntity(juliusId.getGuid());
verifyRelationshipAttributeList(juliusEntity, "subordinates", ImmutableList.of(maxId));
verifyRelationshipAttributeList(juliusEntity, "subordinates", ImmutableList.of(maxId, mikeId));
// Max removed from the subordinate list of Julius
AtlasEntity janeEntity = updatedEntities.getEntity(janeId.getGuid());
......@@ -259,6 +317,48 @@ public abstract class AtlasRelationshipStoreV1Test {
// Jane's subordinates list includes John and Max for soft delete
// Jane's subordinates list includes only John for hard delete
verifyRelationshipAttributeUpdate_NonComposite_OneToMany(janeEntity);
// Remove Mike from Max's friends list
// Max's current friends: [Mike, John]
// Max's updated friends: [Julius, John]
maxEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE);
maxEntityForUpdate.setRelationshipAttribute("friends", ImmutableList.of(johnId, juliusId));
init();
updateResponse = entityStore.updateByUniqueAttributes(employeeType, uniqAttributes , new AtlasEntityWithExtInfo(maxEntityForUpdate));
partialUpdatedEntities = updateResponse.getPartialUpdatedEntities();
assertEquals(partialUpdatedEntities.size(), 3);
// 3 entities should have been updated:
// * Max added Julius and removed Mike from Employee.friends
// * Mike removed Max from Employee.friends
// * Julius added Max in Employee.friends
updatedEntities = entityStore.getByIds(ImmutableList.of(maxId.getGuid(), mikeId.getGuid(), johnId.getGuid(), juliusId.getGuid()));
maxEntity = updatedEntities.getEntity(maxId.getGuid());
juliusEntity = updatedEntities.getEntity(juliusId.getGuid());
AtlasEntity mikeEntity = updatedEntities.getEntity(mikeId.getGuid());
AtlasEntity johnEntity = updatedEntities.getEntity(johnId.getGuid());
verifyRelationshipAttributeUpdate_ManyToMany_Friends(maxEntity, juliusEntity, mikeEntity, johnEntity);
// Remove Julius from Jane's sibling and add Mike as new sibling
AtlasEntity juliusEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE);
juliusEntityForUpdate.setRelationshipAttribute("sibling", mikeId);
init();
updateResponse = entityStore.updateByUniqueAttributes(employeeType, Collections.<String, Object>singletonMap("name", "Julius") , new AtlasEntityWithExtInfo(juliusEntityForUpdate));
partialUpdatedEntities = updateResponse.getPartialUpdatedEntities();
assertEquals(partialUpdatedEntities.size(), 3);
updatedEntities = entityStore.getByIds(ImmutableList.of(juliusId.getGuid(), janeId.getGuid(), mikeId.getGuid()));
juliusEntity = updatedEntities.getEntity(juliusId.getGuid());
janeEntity = updatedEntities.getEntity(janeId.getGuid());
mikeEntity = updatedEntities.getEntity(mikeId.getGuid());
verifyRelationshipAttributeUpdate_OneToOne_Sibling(juliusEntity, janeEntity, mikeEntity);
}
@Test
......@@ -445,12 +545,16 @@ public abstract class AtlasRelationshipStoreV1Test {
protected abstract void verifyRelationshipAttributeUpdate_NonComposite_ManyToOne(AtlasEntity a1, AtlasEntity a2, AtlasEntity a3, AtlasEntity b);
private static void assertObjectIdsContains(List<AtlasObjectId> objectIds, AtlasObjectId objectId) {
protected abstract void verifyRelationshipAttributeUpdate_ManyToMany_Friends(AtlasEntity e1, AtlasEntity e2, AtlasEntity e3, AtlasEntity e4) throws Exception;
protected abstract void verifyRelationshipAttributeUpdate_OneToOne_Sibling(AtlasEntity e1, AtlasEntity e2, AtlasEntity e3) throws Exception;
protected static void assertObjectIdsContains(List<AtlasObjectId> objectIds, AtlasObjectId objectId) {
assertTrue(CollectionUtils.isNotEmpty(objectIds));
assertTrue(objectIds.contains(objectId));
}
private static void assertObjectIdEquals(AtlasObjectId objId1, AtlasObjectId objId2) {
protected static void assertObjectIdEquals(AtlasObjectId objId1, AtlasObjectId objId2) {
assertTrue(objId1.equals(objId2));
}
......@@ -458,7 +562,7 @@ public abstract class AtlasRelationshipStoreV1Test {
assertTrue(collection != null && collection.isEmpty());
}
private static List<AtlasObjectId> toAtlasObjectIds(Object object) {
protected static List<AtlasObjectId> toAtlasObjectIds(Object object) {
List<AtlasObjectId> ret = new ArrayList<>();
if (object instanceof List) {
......@@ -477,7 +581,7 @@ public abstract class AtlasRelationshipStoreV1Test {
return ret;
}
private static AtlasObjectId toAtlasObjectId(Object object) {
protected static AtlasObjectId toAtlasObjectId(Object object) {
if (object instanceof AtlasRelatedObjectId) {
AtlasRelatedObjectId relatedObjectId = (AtlasRelatedObjectId) object;
return new AtlasObjectId(relatedObjectId.getGuid(), relatedObjectId.getTypeName(), relatedObjectId.getUniqueAttributes());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment