ATLAS-1892: update AtlasEntityType to populate relationship attributes during resolve
Signed-off-by: Madhan Neethiraj <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/4f16db45 Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/4f16db45 Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/4f16db45 Branch: refs/heads/feature-odf Commit: 4f16db450921fb90b02e0103392669a389ef9745 Parents: bcb128a Author: Sarath Subramanian <[email protected]> Authored: Thu Jun 22 14:45:42 2017 -0700 Committer: Madhan Neethiraj <[email protected]> Committed: Thu Jun 22 21:42:01 2017 -0700 ---------------------------------------------------------------------- .../atlas/authorize/AtlasResourceTypes.java | 2 +- .../simple/AtlasAuthorizationUtils.java | 6 +- .../atlas/authorize/simple/PolicyParser.java | 4 +- distro/src/conf/policy-store.txt | 8 +- .../java/org/apache/atlas/AtlasErrorCode.java | 1 + .../model/typedef/AtlasRelationshipEndDef.java | 4 - .../org/apache/atlas/type/AtlasEntityType.java | 28 ++-- .../atlas/type/AtlasRelationshipType.java | 60 +++++++- .../atlas/type/TestAtlasRelationshipType.java | 148 +++++++++++++++++++ .../graph/v1/AtlasRelationshipStoreV1.java | 34 ++++- .../apache/atlas/web/rest/RelationshipREST.java | 7 +- 11 files changed, 265 insertions(+), 37 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/authorization/src/main/java/org/apache/atlas/authorize/AtlasResourceTypes.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/AtlasResourceTypes.java b/authorization/src/main/java/org/apache/atlas/authorize/AtlasResourceTypes.java index 925b6b1..9902685 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/AtlasResourceTypes.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/AtlasResourceTypes.java @@ -19,5 +19,5 @@ package org.apache.atlas.authorize; public enum AtlasResourceTypes { - UNKNOWN, ENTITY, TYPE, OPERATION, TAXONOMY, TERM, RELATION + UNKNOWN, ENTITY, TYPE, OPERATION, TAXONOMY, TERM, RELATIONSHIP } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasAuthorizationUtils.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasAuthorizationUtils.java b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasAuthorizationUtils.java index bb3157a..d67376f 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasAuthorizationUtils.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/simple/AtlasAuthorizationUtils.java @@ -1,4 +1,5 @@ /** +/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -31,7 +32,6 @@ import org.slf4j.LoggerFactory; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashSet; -import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; @@ -139,8 +139,8 @@ public class AtlasAuthorizationUtils { if (contextPath.contains("/terms")) { resourceTypes.add(AtlasResourceTypes.TERM); } - } else if (api.startsWith("relation")) { - resourceTypes.add(AtlasResourceTypes.RELATION); + } else if (api.startsWith("relationship")) { + resourceTypes.add(AtlasResourceTypes.RELATIONSHIP); } else { LOG.error("Unable to find Atlas Resource corresponding to : {}\nSetting {}" , api, AtlasResourceTypes.UNKNOWN.name()); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/authorization/src/main/java/org/apache/atlas/authorize/simple/PolicyParser.java ---------------------------------------------------------------------- diff --git a/authorization/src/main/java/org/apache/atlas/authorize/simple/PolicyParser.java b/authorization/src/main/java/org/apache/atlas/authorize/simple/PolicyParser.java index acf7388..fc611c8 100644 --- a/authorization/src/main/java/org/apache/atlas/authorize/simple/PolicyParser.java +++ b/authorization/src/main/java/org/apache/atlas/authorize/simple/PolicyParser.java @@ -231,8 +231,8 @@ public class PolicyParser { resourceType = AtlasResourceTypes.TAXONOMY; } else if (type.equalsIgnoreCase("TERM")) { resourceType = AtlasResourceTypes.TERM; - } else if (type.equalsIgnoreCase("RELATION")) { - resourceType = AtlasResourceTypes.RELATION; + } else if (type.equalsIgnoreCase("RELATIONSHIP")) { + resourceType = AtlasResourceTypes.RELATIONSHIP; } else { Log.warn(type + " is invalid resource please check PolicyStore file"); continue; http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/distro/src/conf/policy-store.txt ---------------------------------------------------------------------- diff --git a/distro/src/conf/policy-store.txt b/distro/src/conf/policy-store.txt index 47583c1..c804b8d 100644 --- a/distro/src/conf/policy-store.txt +++ b/distro/src/conf/policy-store.txt @@ -2,8 +2,8 @@ ##r-READ, w-WRITE, u-UPDATE, d-DELETE ##Policy_Name;;User_Name1:Operations_Allowed,User_Name2:Operations_Allowed;;Group_Name1:Operations_Allowed,Group_Name2:Operations_Allowed;;Resource_Type1:Resource_Name,Resource_Type2:Resource_Name ## -adminPolicy;;admin:rwud;;ROLE_ADMIN:rwud;;type:*,entity:*,operation:*,taxonomy:*,term:* -dataScientistPolicy;;;;DATA_SCIENTIST:r;;type:*,entity:*,taxonomy:*,term:* -dataStewardPolicy;;;;DATA_STEWARD:rwu;;type:*,entity:*,taxonomy:*,term:* -hadoopPolicy;;;;hadoop:rwud;;type:*,entity:*,operation:*,taxonomy:*,term:* +adminPolicy;;admin:rwud;;ROLE_ADMIN:rwud;;type:*,entity:*,operation:*,taxonomy:*,term:*,relationship:* +dataScientistPolicy;;;;DATA_SCIENTIST:r;;type:*,entity:*,taxonomy:*,term:*,relationship:* +dataStewardPolicy;;;;DATA_STEWARD:rwu;;type:*,entity:*,taxonomy:*,term:*,relationship:* +hadoopPolicy;;;;hadoop:rwud;;type:*,entity:*,operation:*,taxonomy:*,term:*,relationship:* rangerTagSyncPolicy;;;;RANGER_TAG_SYNC:r;;type:*,entity:* http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/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 e8971a8..70480df 100644 --- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java +++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java @@ -93,6 +93,7 @@ public enum AtlasErrorCode { REFERENCED_ENTITY_NOT_FOUND(404, "ATLAS-404-00-00A", "Referenced entity {0} is not found"), INSTANCE_NOT_FOUND(404, "ATLAS-404-00-00B", "Given instance is invalid/not found: {0}"), RELATIONSHIP_GUID_NOT_FOUND(404, "ATLAS-404-00-00C", "Given relationship guid {0} is invalid/not found"), + RELATIONSHIP_CRUD_INVALID_PARAMS(404, "ATLAS-404-00-00D", "Invalid relationship creation/updation parameters passed : {0}"), // All data conflict errors go here TYPE_ALREADY_EXISTS(409, "ATLAS-409-00-001", "Given type {0} already exists"), http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/intg/src/main/java/org/apache/atlas/model/typedef/AtlasRelationshipEndDef.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/model/typedef/AtlasRelationshipEndDef.java b/intg/src/main/java/org/apache/atlas/model/typedef/AtlasRelationshipEndDef.java index 34e932e..f80ea89 100644 --- a/intg/src/main/java/org/apache/atlas/model/typedef/AtlasRelationshipEndDef.java +++ b/intg/src/main/java/org/apache/atlas/model/typedef/AtlasRelationshipEndDef.java @@ -166,10 +166,6 @@ public class AtlasRelationshipEndDef implements Serializable { return this.cardinality; } - public boolean isContainer() { return isContainer; } - - public void setContainer(boolean container) { isContainer = container; } - public String getLegacyLabel() { return legacyLabel; } public void setLegacyLabel(String legacyLabel) { this.legacyLabel = legacyLabel; } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java index a29f7fb..70e3067 100644 --- a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java +++ b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java @@ -47,10 +47,11 @@ public class AtlasEntityType extends AtlasStructType { private final AtlasEntityDef entityDef; - private List<AtlasEntityType> superTypes = Collections.emptyList(); - private Set<String> allSuperTypes = Collections.emptySet(); - private Set<String> allSubTypes = Collections.emptySet(); - private Set<String> typeAndAllSubTypes = Collections.emptySet(); + private List<AtlasEntityType> superTypes = Collections.emptyList(); + private Set<String> allSuperTypes = Collections.emptySet(); + private Set<String> allSubTypes = Collections.emptySet(); + private Set<String> typeAndAllSubTypes = Collections.emptySet(); + private Map<String, AtlasAttribute> relationshipAttributes = Collections.emptyMap(); public AtlasEntityType(AtlasEntityDef entityDef) { super(entityDef); @@ -88,12 +89,13 @@ public class AtlasEntityType extends AtlasStructType { } } - this.superTypes = Collections.unmodifiableList(s); - this.allSuperTypes = Collections.unmodifiableSet(allS); - this.allAttributes = Collections.unmodifiableMap(allA); - this.uniqAttributes = getUniqueAttributes(this.allAttributes); - this.allSubTypes = new HashSet<>(); // this will be populated in resolveReferencesPhase2() - this.typeAndAllSubTypes = new HashSet<>(); // this will be populated in resolveReferencesPhase2() + this.superTypes = Collections.unmodifiableList(s); + this.allSuperTypes = Collections.unmodifiableSet(allS); + this.allAttributes = Collections.unmodifiableMap(allA); + this.uniqAttributes = getUniqueAttributes(this.allAttributes); + this.allSubTypes = new HashSet<>(); // this will be populated in resolveReferencesPhase2() + this.typeAndAllSubTypes = new HashSet<>(); // this will be populated in resolveReferencesPhase2() + this.relationshipAttributes = new HashMap<>(); // this will be populated in resolveReferencesPhase2() this.typeAndAllSubTypes.add(this.getTypeName()); } @@ -140,6 +142,12 @@ public class AtlasEntityType extends AtlasStructType { return StringUtils.isNotEmpty(entityTypeName) && allSuperTypes.contains(entityTypeName); } + public Map<String, AtlasAttribute> getRelationshipAttributes() { return Collections.unmodifiableMap(relationshipAttributes); } + + public void addRelationshipAttribute(String attributeName, AtlasAttribute attribute) { + relationshipAttributes.put(attributeName, attribute); + } + @Override public AtlasEntity createDefaultValue() { AtlasEntity ret = new AtlasEntity(entityDef.getName()); http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/intg/src/main/java/org/apache/atlas/type/AtlasRelationshipType.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasRelationshipType.java b/intg/src/main/java/org/apache/atlas/type/AtlasRelationshipType.java index 38b68bb..f85cf35 100644 --- a/intg/src/main/java/org/apache/atlas/type/AtlasRelationshipType.java +++ b/intg/src/main/java/org/apache/atlas/type/AtlasRelationshipType.java @@ -20,14 +20,16 @@ package org.apache.atlas.type; import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.typedef.AtlasBaseTypeDef; import org.apache.atlas.model.typedef.AtlasRelationshipDef; import org.apache.atlas.model.typedef.AtlasRelationshipDef.RelationshipCategory; import org.apache.atlas.model.typedef.AtlasRelationshipEndDef; import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef; +import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef.Cardinality; +import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - /** * class that implements behaviour of an relationship-type. */ @@ -57,20 +59,26 @@ public class AtlasRelationshipType extends AtlasStructType { public void resolveReferences(AtlasTypeRegistry typeRegistry) throws AtlasBaseException { super.resolveReferences(typeRegistry); - String end1TypeName = relationshipDef != null && relationshipDef.getEndDef1() != null ? relationshipDef.getEndDef1().getType() : null; - String end2TypeName = relationshipDef != null && relationshipDef.getEndDef2() != null ? relationshipDef.getEndDef2().getType() : null; + if (relationshipDef == null) { + throw new AtlasBaseException(AtlasErrorCode.INVALID_VALUE, "relationshipDef is null"); + } + + String end1TypeName = relationshipDef.getEndDef1() != null ? relationshipDef.getEndDef1().getType() : null; + String end2TypeName = relationshipDef.getEndDef2() != null ? relationshipDef.getEndDef2().getType() : null; AtlasType type1 = typeRegistry.getType(end1TypeName); AtlasType type2 = typeRegistry.getType(end2TypeName); if (type1 instanceof AtlasEntityType) { - end1Type = (AtlasEntityType)type1; + end1Type = (AtlasEntityType) type1; + } else { throw new AtlasBaseException(AtlasErrorCode.RELATIONSHIPDEF_INVALID_END_TYPE, getTypeName(), end1TypeName); } if (type2 instanceof AtlasEntityType) { - end2Type = (AtlasEntityType)type2; + end2Type = (AtlasEntityType) type2; + } else { throw new AtlasBaseException(AtlasErrorCode.RELATIONSHIPDEF_INVALID_END_TYPE, getTypeName(), end2TypeName); } @@ -79,12 +87,25 @@ public class AtlasRelationshipType extends AtlasStructType { } @Override + public void resolveReferencesPhase2(AtlasTypeRegistry typeRegistry) throws AtlasBaseException { + super.resolveReferencesPhase2(typeRegistry); + + addRelationshipAttributeToEndType(relationshipDef.getEndDef1(), end1Type, end2Type.getTypeName(), typeRegistry); + + addRelationshipAttributeToEndType(relationshipDef.getEndDef2(), end2Type, end1Type.getTypeName(), typeRegistry); + } + + @Override public boolean isValidValue(Object obj) { boolean ret = true; if (obj != null) { - validateAtlasRelationshipType((AtlasRelationshipType) obj); - ret = super.isValidValue(obj); + + if (obj instanceof AtlasRelationshipType) { + validateAtlasRelationshipType((AtlasRelationshipType) obj); + } + + ret = super.isValidValue(obj); } return ret; @@ -176,4 +197,29 @@ public class AtlasRelationshipType extends AtlasStructType { } } } + + private void addRelationshipAttributeToEndType(AtlasRelationshipEndDef endDef, + AtlasEntityType entityType, + String attrTypeName, + AtlasTypeRegistry typeRegistry) throws AtlasBaseException { + + String attrName = (endDef != null) ? endDef.getName() : null; + + if (StringUtils.isEmpty(attrName)) { + return; + } + + AtlasAttribute attribute = entityType.getAttribute(attrName); + + if (attribute == null) { //attr doesn't exist in type - is a new relationship attribute + + if (endDef.getCardinality() == Cardinality.SET) { + attrTypeName = AtlasBaseTypeDef.getArrayTypeName(attrTypeName); + } + + attribute = new AtlasAttribute(entityType, new AtlasAttributeDef(attrName, attrTypeName), typeRegistry.getType(attrTypeName)); + } + + entityType.addRelationshipAttribute(attrName, attribute); + } } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/intg/src/test/java/org/apache/atlas/type/TestAtlasRelationshipType.java ---------------------------------------------------------------------- diff --git a/intg/src/test/java/org/apache/atlas/type/TestAtlasRelationshipType.java b/intg/src/test/java/org/apache/atlas/type/TestAtlasRelationshipType.java index 7a4e9fd..41aac8f 100644 --- a/intg/src/test/java/org/apache/atlas/type/TestAtlasRelationshipType.java +++ b/intg/src/test/java/org/apache/atlas/type/TestAtlasRelationshipType.java @@ -17,15 +17,48 @@ */ package org.apache.atlas.type; +import com.google.common.collect.ImmutableSet; import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.typedef.AtlasBaseTypeDef; +import org.apache.atlas.type.AtlasStructType.AtlasAttribute; +import org.apache.atlas.type.AtlasTypeRegistry.AtlasTransientTypeRegistry; +import org.apache.atlas.model.typedef.AtlasEntityDef; import org.apache.atlas.model.typedef.AtlasRelationshipDef; +import org.apache.atlas.model.typedef.AtlasRelationshipDef.PropagateTags; +import org.apache.atlas.model.typedef.AtlasRelationshipDef.RelationshipCategory; import org.apache.atlas.model.typedef.AtlasRelationshipEndDef; import org.apache.atlas.model.typedef.AtlasStructDef; +import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef.Cardinality; +import org.testng.Assert; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + import static org.testng.Assert.fail; + public class TestAtlasRelationshipType { + + private AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry(); + + private static final String EMPLOYEE_TYPE = "employee"; + private static final String DEPARTMENT_TYPE = "department"; + private static final String ADDRESS_TYPE = "address"; + private static final String PHONE_TYPE = "phone"; + private static final String DEPT_EMPLOYEE_RELATION_TYPE = "departmentEmployee"; + private static final String EMPLOYEE_ADDRESS_RELATION_TYPE = "employeeAddress"; + private static final String EMPLOYEE_PHONE_RELATION_TYPE = "employeePhone"; + + @Test + public void createTypesAndRelationships() throws AtlasBaseException { + createEmployeeTypes(); + + createRelationshipTypes(); + } + @Test public void testvalidateAtlasRelationshipDef() throws AtlasBaseException { AtlasRelationshipEndDef ep1 = new AtlasRelationshipEndDef("typeA", "attr1", AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE); @@ -104,4 +137,119 @@ public class TestAtlasRelationshipType { } } + + @Test(dependsOnMethods = "createTypesAndRelationships") + public void testRelationshipAttributes() throws Exception { + Map<String, AtlasAttribute> employeeRelationAttrs = getRelationAttrsForType(EMPLOYEE_TYPE); + + Assert.assertNotNull(employeeRelationAttrs); + Assert.assertEquals(employeeRelationAttrs.size(), 2); + + Assert.assertTrue(employeeRelationAttrs.containsKey("department")); + Assert.assertTrue(employeeRelationAttrs.containsKey("address")); + + AtlasAttribute deptAttr = employeeRelationAttrs.get("department"); + Assert.assertEquals(deptAttr.getTypeName(), DEPARTMENT_TYPE); + + AtlasAttribute addrAttr = employeeRelationAttrs.get("address"); + Assert.assertEquals(addrAttr.getTypeName(), ADDRESS_TYPE); + + Map<String, AtlasAttribute> deptRelationAttrs = getRelationAttrsForType(DEPARTMENT_TYPE); + + Assert.assertNotNull(deptRelationAttrs); + Assert.assertEquals(deptRelationAttrs.size(), 1); + Assert.assertTrue(deptRelationAttrs.containsKey("employees")); + + AtlasAttribute employeesAttr = deptRelationAttrs.get("employees"); + Assert.assertEquals(employeesAttr.getTypeName(),AtlasBaseTypeDef.getArrayTypeName(EMPLOYEE_TYPE)); + + Map<String, AtlasAttribute> addressRelationAttrs = getRelationAttrsForType(ADDRESS_TYPE); + + Assert.assertNotNull(addressRelationAttrs); + Assert.assertEquals(addressRelationAttrs.size(), 1); + Assert.assertTrue(addressRelationAttrs.containsKey("employees")); + + AtlasAttribute employeesAttr1 = addressRelationAttrs.get("employees"); + Assert.assertEquals(employeesAttr1.getTypeName(),AtlasBaseTypeDef.getArrayTypeName(EMPLOYEE_TYPE)); + } + + @Test(dependsOnMethods = "testRelationshipAttributes") + public void testRelationshipAttributesOnExistingAttributes() throws Exception { + AtlasRelationshipDef employeePhoneRelationDef = new AtlasRelationshipDef(EMPLOYEE_PHONE_RELATION_TYPE, getDescription(EMPLOYEE_PHONE_RELATION_TYPE), "1.0", + RelationshipCategory.ASSOCIATION, PropagateTags.ONE_TO_TWO, + new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "phone_no", Cardinality.SINGLE), + new AtlasRelationshipEndDef(PHONE_TYPE, "owner", Cardinality.SINGLE)); + + createType(employeePhoneRelationDef); + + Map<String, AtlasAttribute> employeeRelationshipAttrs = getRelationAttrsForType(EMPLOYEE_TYPE); + Map<String, AtlasAttribute> employeeAttrs = getAttrsForType(EMPLOYEE_TYPE); + + // validate if phone_no exists in both relationAttributes and attributes + Assert.assertTrue(employeeRelationshipAttrs.containsKey("phone_no")); + Assert.assertTrue(employeeAttrs.containsKey("phone_no")); + } + + private void createEmployeeTypes() throws AtlasBaseException { + AtlasEntityDef phoneDef = AtlasTypeUtil.createClassTypeDef(PHONE_TYPE, getDescription(PHONE_TYPE), ImmutableSet.<String>of(), + AtlasTypeUtil.createRequiredAttrDef("phone_number", "int"), + AtlasTypeUtil.createOptionalAttrDef("area_code", "int"), + AtlasTypeUtil.createOptionalAttrDef("owner", EMPLOYEE_TYPE)); + + AtlasEntityDef employeeDef = AtlasTypeUtil.createClassTypeDef(EMPLOYEE_TYPE, getDescription(EMPLOYEE_TYPE), ImmutableSet.<String>of(), + AtlasTypeUtil.createRequiredAttrDef("name", "string"), + AtlasTypeUtil.createOptionalAttrDef("dob", "date"), + AtlasTypeUtil.createOptionalAttrDef("age", "int"), + AtlasTypeUtil.createRequiredAttrDef("phone_no", PHONE_TYPE)); + + AtlasEntityDef departmentDef = AtlasTypeUtil.createClassTypeDef(DEPARTMENT_TYPE, getDescription(DEPARTMENT_TYPE), ImmutableSet.<String>of(), + AtlasTypeUtil.createRequiredAttrDef("name", "string"), + AtlasTypeUtil.createOptionalAttrDef("count", "int")); + + AtlasEntityDef addressDef = AtlasTypeUtil.createClassTypeDef(ADDRESS_TYPE, getDescription(ADDRESS_TYPE), ImmutableSet.<String>of(), + AtlasTypeUtil.createOptionalAttrDef("street", "string"), + AtlasTypeUtil.createRequiredAttrDef("city", "string"), + AtlasTypeUtil.createRequiredAttrDef("state", "string"), + AtlasTypeUtil.createOptionalAttrDef("zip", "int")); + + createTypes(new ArrayList<>(Arrays.asList(phoneDef, employeeDef, departmentDef, addressDef))); + } + + private void createRelationshipTypes() throws AtlasBaseException { + AtlasRelationshipDef deptEmployeeRelationDef = new AtlasRelationshipDef(DEPT_EMPLOYEE_RELATION_TYPE, getDescription(DEPT_EMPLOYEE_RELATION_TYPE), "1.0", + RelationshipCategory.ASSOCIATION, PropagateTags.ONE_TO_TWO, + new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "department", Cardinality.SINGLE), + new AtlasRelationshipEndDef(DEPARTMENT_TYPE, "employees", Cardinality.SET)); + + AtlasRelationshipDef employeeAddrRelationDef = new AtlasRelationshipDef(EMPLOYEE_ADDRESS_RELATION_TYPE, getDescription(EMPLOYEE_ADDRESS_RELATION_TYPE), "1.0", + RelationshipCategory.ASSOCIATION, PropagateTags.ONE_TO_TWO, + new AtlasRelationshipEndDef(EMPLOYEE_TYPE, "address", Cardinality.SINGLE), + new AtlasRelationshipEndDef(ADDRESS_TYPE, "employees", Cardinality.SET)); + + createTypes(new ArrayList<>(Arrays.asList(deptEmployeeRelationDef, employeeAddrRelationDef))); + } + + private void createType(AtlasBaseTypeDef typeDef) throws AtlasBaseException { + createTypes(new ArrayList<>(Arrays.asList(typeDef))); + } + + private void createTypes(List<? extends AtlasBaseTypeDef> typeDefs) throws AtlasBaseException { + AtlasTransientTypeRegistry ttr = typeRegistry.lockTypeRegistryForUpdate(); + + ttr.addTypes(typeDefs); + + typeRegistry.releaseTypeRegistryForUpdate(ttr, true); + } + + private String getDescription(String typeName) { + return typeName + " description"; + } + + private Map<String, AtlasAttribute> getRelationAttrsForType(String typeName) { + return typeRegistry.getEntityTypeByName(typeName).getRelationshipAttributes(); + } + + private Map<String, AtlasAttribute> getAttrsForType(String typeName) { + return typeRegistry.getEntityTypeByName(typeName).getAllAttributes(); + } } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1.java index 8fe4888..8621233 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1.java @@ -20,6 +20,7 @@ package org.apache.atlas.repository.store.graph.v1; import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.annotation.GraphTransaction; import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.TypeCategory; import org.apache.atlas.model.instance.AtlasObjectId; import org.apache.atlas.model.instance.AtlasRelationship; import org.apache.atlas.model.typedef.AtlasRelationshipDef; @@ -29,11 +30,9 @@ 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.AtlasVertex; -import org.apache.atlas.repository.store.graph.AtlasRelationshipDefStore; import org.apache.atlas.repository.store.graph.AtlasRelationshipStore; import org.apache.atlas.type.AtlasEntityType; import org.apache.atlas.type.AtlasRelationshipType; -import org.apache.atlas.type.AtlasStructType; import org.apache.atlas.type.AtlasStructType.AtlasAttribute; import org.apache.atlas.type.AtlasType; import org.apache.atlas.type.AtlasTypeRegistry; @@ -46,13 +45,16 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.inject.Inject; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Map; import java.util.UUID; @Component public class AtlasRelationshipStoreV1 implements AtlasRelationshipStore { private static final Logger LOG = LoggerFactory.getLogger(AtlasRelationshipStoreV1.class); + private static final int DEFAULT_RELATIONSHIP_VERSION = 0; private final AtlasTypeRegistry typeRegistry; private final EntityGraphRetriever entityRetriever; @@ -182,7 +184,7 @@ public class AtlasRelationshipStoreV1 implements AtlasRelationshipStore { AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(relationshipName); if (relationshipType == null) { - throw new AtlasBaseException(AtlasErrorCode.INVALID_VALUE, "unknown relationship '" + relationshipName + "'"); + throw new AtlasBaseException(AtlasErrorCode.INVALID_VALUE, "unknown relationship type'" + relationshipName + "'"); } AtlasObjectId end1 = relationship.getEnd1(); @@ -222,6 +224,8 @@ public class AtlasRelationshipStoreV1 implements AtlasRelationshipStore { validateEnd(end1); validateEnd(end2); + + validateAndNormalize(relationship); } private void validateEnd(AtlasObjectId end) throws AtlasBaseException { @@ -241,6 +245,28 @@ public class AtlasRelationshipStoreV1 implements AtlasRelationshipStore { } } + private void validateAndNormalize(AtlasRelationship relationship) throws AtlasBaseException { + List<String> messages = new ArrayList<>(); + + if (! AtlasTypeUtil.isValidGuid(relationship.getGuid())) { + throw new AtlasBaseException(AtlasErrorCode.RELATIONSHIP_GUID_NOT_FOUND, relationship.getGuid()); + } + + AtlasRelationshipType type = typeRegistry.getRelationshipTypeByName(relationship.getTypeName()); + + if (type == null) { + throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_INVALID, TypeCategory.RELATIONSHIP.name(), relationship.getTypeName()); + } + + type.validateValue(relationship, relationship.getTypeName(), messages); + + if (!messages.isEmpty()) { + throw new AtlasBaseException(AtlasErrorCode.RELATIONSHIP_CRUD_INVALID_PARAMS, messages); + } + + type.getNormalizedValue(relationship); + } + private AtlasEdge getRelationshipEdge(AtlasVertex fromVertex, AtlasVertex toVertex, String relationshipLabel) { AtlasEdge ret = graphHelper.getEdgeForLabel(fromVertex, relationshipLabel); @@ -261,7 +287,7 @@ public class AtlasRelationshipStoreV1 implements AtlasRelationshipStore { private int getRelationVersion(AtlasRelationship relationship) { Long ret = relationship != null ? relationship.getVersion() : null; - return (ret != null) ? ret.intValue() : 0; + return (ret != null) ? ret.intValue() : DEFAULT_RELATIONSHIP_VERSION; } private AtlasVertex getVertexFromEndPoint(AtlasObjectId endPoint) { http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/4f16db45/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java ---------------------------------------------------------------------- diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java index 144080a..7174543 100644 --- a/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java +++ b/webapp/src/main/java/org/apache/atlas/web/rest/RelationshipREST.java @@ -40,7 +40,7 @@ import javax.ws.rs.Produces; /** * REST interface for entity relationships. */ -@Path("v2/relation") +@Path("v2/relationship") @Singleton @Service public class RelationshipREST { @@ -68,6 +68,7 @@ public class RelationshipREST { } return relationshipStore.create(relationship); + } finally { AtlasPerfTracer.log(perf); } @@ -88,6 +89,7 @@ public class RelationshipREST { } return relationshipStore.update(relationship); + } finally { AtlasPerfTracer.log(perf); } @@ -109,6 +111,7 @@ public class RelationshipREST { } return relationshipStore.getById(guid); + } finally { AtlasPerfTracer.log(perf); } @@ -134,4 +137,4 @@ public class RelationshipREST { AtlasPerfTracer.log(perf); } } -} +} \ No newline at end of file
