This is an automated email from the ASF dual-hosted git repository.
sarath pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/master by this push:
new 1b0dff8 ATLAS-4522: Updating typedef with new supertype should be
allowed only if attributes are unique compared to other existing supertypes
1b0dff8 is described below
commit 1b0dff89e26ff06f7b14456369975fe696f05ebc
Author: Radhika Kundam <[email protected]>
AuthorDate: Wed Jan 5 17:38:52 2022 -0500
ATLAS-4522: Updating typedef with new supertype should be allowed only if
attributes are unique compared to other existing supertypes
Signed-off-by: Sarath Subramanian <[email protected]>
---
.../main/java/org/apache/atlas/AtlasErrorCode.java | 1 +
.../org/apache/atlas/type/AtlasEntityType.java | 18 ++++--
.../apache/atlas/type/TestAtlasTypeRegistry.java | 66 ++++++++++++++++++++++
.../store/graph/v2/EntityGraphRetriever.java | 2 +
.../store/graph/v2/AtlasEntityStoreV2Test.java | 5 +-
.../web/integration/TypedefsJerseyResourceIT.java | 3 +-
.../web/integration/TypesJerseyResourceIT.java | 3 +-
7 files changed, 90 insertions(+), 8 deletions(-)
diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
index 9d11820..c7e6f3a 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
@@ -173,6 +173,7 @@ public enum AtlasErrorCode {
NO_DATA_FOUND(400, "ATLAS-400-00-09B", "No data found in the uploaded
file"),
NOT_VALID_FILE(400, "ATLAS-400-00-09C", "Invalid {0} file"),
ATTRIBUTE_NAME_ALREADY_EXISTS_IN_PARENT_TYPE(400, "ATLAS-400-00-09D",
"Invalid attribute name: {0}.{1}. Attribute already exists in parent type:
{2}"),
+ ATTRIBUTE_NAME_ALREADY_EXISTS_IN_ANOTHER_PARENT_TYPE(400,
"ATLAS-400-00-09E", "Invalid attribute name: {0}.{1}. Attribute already exists
in another parent type: {2}"),
UNAUTHORIZED_ACCESS(403, "ATLAS-403-00-001", "{0} is not authorized to
perform {1}"),
// All Not found enums go here
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 6d83599..76bee36 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
@@ -843,9 +843,10 @@ public class AtlasEntityType extends AtlasStructType {
private void getTypeHierarchyInfo(AtlasTypeRegistry typeRegistry,
Set<String> allSuperTypeNames,
Map<String, AtlasAttribute>
allAttributes) throws AtlasBaseException {
- List<String> visitedTypes = new ArrayList<>();
+ List<String> visitedTypes = new ArrayList<>();
+ Map<String, String> attributeToEntityNameMap = new HashMap<>();
- collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames,
allAttributes, visitedTypes);
+ collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames,
allAttributes, attributeToEntityNameMap, visitedTypes);
}
@@ -858,6 +859,7 @@ public class AtlasEntityType extends AtlasStructType {
private void collectTypeHierarchyInfo(AtlasTypeRegistry typeRegistry,
Set<String> allSuperTypeNames,
Map<String, AtlasAttribute>
allAttributes,
+ Map<String, String>
attributeToEntityNameMap,
List<String> visitedTypes) throws
AtlasBaseException {
if (visitedTypes.contains(entityDef.getName())) {
throw new AtlasBaseException(AtlasErrorCode.CIRCULAR_REFERENCE,
entityDef.getName(),
@@ -870,7 +872,7 @@ public class AtlasEntityType extends AtlasStructType {
AtlasEntityType superType =
typeRegistry.getEntityTypeByName(superTypeName);
if (superType != null) {
- superType.collectTypeHierarchyInfo(typeRegistry,
allSuperTypeNames, allAttributes, visitedTypes);
+ superType.collectTypeHierarchyInfo(typeRegistry,
allSuperTypeNames, allAttributes, attributeToEntityNameMap, visitedTypes);
}
}
visitedTypes.remove(entityDef.getName());
@@ -879,9 +881,15 @@ public class AtlasEntityType extends AtlasStructType {
if (CollectionUtils.isNotEmpty(entityDef.getAttributeDefs())) {
for (AtlasAttributeDef attributeDef :
entityDef.getAttributeDefs()) {
+ AtlasType type =
typeRegistry.getType(attributeDef.getTypeName());
+ String attributeName = attributeDef.getName();
- AtlasType type =
typeRegistry.getType(attributeDef.getTypeName());
- allAttributes.put(attributeDef.getName(), new
AtlasAttribute(this, attributeDef, type));
+ if (attributeToEntityNameMap.containsKey(attributeName) &&
!attributeToEntityNameMap.get(attributeName).equals(entityDef.getName())) {
+ throw new
AtlasBaseException(AtlasErrorCode.ATTRIBUTE_NAME_ALREADY_EXISTS_IN_ANOTHER_PARENT_TYPE,
entityDef.getName(), attributeName,
attributeToEntityNameMap.get(attributeName));
+ }
+
+ allAttributes.put(attributeName, new AtlasAttribute(this,
attributeDef, type));
+ attributeToEntityNameMap.put(attributeName,
entityDef.getName());
}
}
}
diff --git
a/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
b/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
index 3b55a63..85d041b 100644
--- a/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
+++ b/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
@@ -593,6 +593,72 @@ public class TestAtlasTypeRegistry {
validateAllSubTypes(typeRegistry, "L1", new HashSet<String>());
}
+ /* create 2 entity types: L0 and L1, with L0 as superType of L1
+ * Create entity type L2 with same attribute as in L0.
+ * Add L2 as superType of L1 - this should fail as "attr1" already exists
in other supertype L0
+ * verify that after the update failure, the registry still has correct
super-type/sub-type information for L1
+ */
+ @Test
+ public void testRegistryValiditySuperTypesUpdateWithExistingAttribute()
throws AtlasBaseException {
+ AtlasEntityDef entL0 = new AtlasEntityDef("L0");
+ AtlasEntityDef entL1 = new AtlasEntityDef("L1");
+ AtlasEntityDef entL2 = new AtlasEntityDef("L2");
+
+ entL1.addSuperType(entL0.getName());
+
+ entL0.addAttribute(new AtlasAttributeDef("attr1",
AtlasBaseTypeDef.ATLAS_TYPE_INT));
+ entL1.addAttribute(new AtlasAttributeDef("attr2",
AtlasBaseTypeDef.ATLAS_TYPE_INT));
+ entL2.addAttribute(new AtlasAttributeDef("attr1",
AtlasBaseTypeDef.ATLAS_TYPE_INT));
+
+ AtlasTypesDef typesDef = new AtlasTypesDef();
+
+ typesDef.getEntityDefs().add(entL0);
+ typesDef.getEntityDefs().add(entL1);
+ typesDef.getEntityDefs().add(entL2);
+
+ AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
+ AtlasTransientTypeRegistry ttr = null;
+ boolean commit = false;
+ String failureMsg = null;
+
+ try {
+ ttr = typeRegistry.lockTypeRegistryForUpdate();
+
+ ttr.addTypes(typesDef);
+
+ commit = true;
+ } catch (AtlasBaseException excp) {
+ failureMsg = excp.getMessage();
+ } finally {
+ typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
+ }
+ assertNull(failureMsg);
+
+ validateAllSuperTypes(typeRegistry, "L1", new
HashSet<>(Arrays.asList("L0")));
+ validateAllSubTypes(typeRegistry, "L1", new HashSet<String>());
+
+ //Add L2 as supertype for L1
+ entL1.addSuperType(entL2.getName());
+
+ try {
+ commit = false;
+
+ ttr = typeRegistry.lockTypeRegistryForUpdate();
+
+ ttr.updateTypes(typesDef);
+
+ commit = true;
+ } catch (AtlasBaseException excp) {
+ failureMsg = excp.getMessage();
+ } finally {
+ typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
+ }
+ assertNotNull(failureMsg);
+
+ validateAllSuperTypes(typeRegistry, "L1", new
HashSet<>(Arrays.asList("L0")));
+ validateAllSubTypes(typeRegistry, "L1", new HashSet<String>());
+ }
+
private boolean addType(AtlasTypeRegistry typeRegistry, AtlasBaseTypeDef
typeDef) {
boolean ret = false;
AtlasTransientTypeRegistry ttr = null;
diff --git
a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java
b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java
index 7948475..9671df9 100644
---
a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java
+++
b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java
@@ -741,6 +741,8 @@ public class EntityGraphRetriever {
if (attrValue != null) {
ret.setAttribute(headerAttribute.getName(), attrValue);
+ } else {
+ ret.setAttribute(headerAttribute.getName(),
StringUtils.EMPTY);
}
}
diff --git
a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2Test.java
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2Test.java
index 9aced8e..1489b27 100644
---
a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2Test.java
+++
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2Test.java
@@ -42,6 +42,8 @@ import org.apache.atlas.model.typedef.AtlasTypesDef;
import org.apache.atlas.type.AtlasTypeUtil;
import org.apache.atlas.util.FileUtils;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
@@ -537,7 +539,8 @@ public class AtlasEntityStoreV2Test extends
AtlasEntityTestBase {
init();
response = entityStore.createOrUpdate(new
AtlasEntityStream(entitiesInfo), false);
updatedTable = response.getFirstUpdatedEntityByTypeName(TABLE_TYPE);
- Assert.assertNull(updatedTable.getAttribute("description"));
+ Object updatedDescription =
ObjectUtils.defaultIfNull(updatedTable.getAttribute("description"),
StringUtils.EMPTY);
+ Assert.assertTrue(StringUtils.isEmpty(updatedDescription.toString()));
validateEntity(entitiesInfo, getEntityFromStore(updatedTable));
}
diff --git
a/webapp/src/test/java/org/apache/atlas/web/integration/TypedefsJerseyResourceIT.java
b/webapp/src/test/java/org/apache/atlas/web/integration/TypedefsJerseyResourceIT.java
index 9506c62..d1aea9d 100644
---
a/webapp/src/test/java/org/apache/atlas/web/integration/TypedefsJerseyResourceIT.java
+++
b/webapp/src/test/java/org/apache/atlas/web/integration/TypedefsJerseyResourceIT.java
@@ -338,9 +338,10 @@ public class TypedefsJerseyResourceIT extends
BaseResourceIT {
@Test
public void testListTypesByFilter() throws Exception {
AtlasAttributeDef attr = AtlasTypeUtil.createOptionalAttrDef("attr",
"string");
+ AtlasAttributeDef attr1 = AtlasTypeUtil.createOptionalAttrDef("attr1",
"string");
AtlasEntityDef classDefA = AtlasTypeUtil.createClassTypeDef("A" +
randomString(), Collections.<String>emptySet(), attr);
AtlasEntityDef classDefA1 = AtlasTypeUtil.createClassTypeDef("A1" +
randomString(), Collections.singleton(classDefA.getName()));
- AtlasEntityDef classDefB = AtlasTypeUtil.createClassTypeDef("B" +
randomString(), Collections.<String>emptySet(), attr);
+ AtlasEntityDef classDefB = AtlasTypeUtil.createClassTypeDef("B" +
randomString(), Collections.<String>emptySet(), attr1);
AtlasEntityDef classDefC = AtlasTypeUtil.createClassTypeDef("C" +
randomString(), new HashSet<>(Arrays.asList(classDefB.getName(),
classDefA.getName())));
AtlasTypesDef atlasTypesDef = new AtlasTypesDef();
diff --git
a/webapp/src/test/java/org/apache/atlas/web/integration/TypesJerseyResourceIT.java
b/webapp/src/test/java/org/apache/atlas/web/integration/TypesJerseyResourceIT.java
index 6a0bbec..885fe85 100755
---
a/webapp/src/test/java/org/apache/atlas/web/integration/TypesJerseyResourceIT.java
+++
b/webapp/src/test/java/org/apache/atlas/web/integration/TypesJerseyResourceIT.java
@@ -211,6 +211,7 @@ public class TypesJerseyResourceIT extends BaseResourceIT {
@Test
public void testListTypesByFilter() throws Exception {
AttributeDefinition attr = TypesUtil.createOptionalAttrDef("attr",
AtlasBaseTypeDef.ATLAS_TYPE_STRING);
+ AttributeDefinition attr1 = TypesUtil.createOptionalAttrDef("attr1",
AtlasBaseTypeDef.ATLAS_TYPE_STRING);
ClassTypeDefinition classTypeDef = TypesUtil.createClassTypeDef("A" +
randomString(), null, Collections.emptySet(), attr);
TypesDef typesDef = new TypesDef(Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Collections.singletonList(classTypeDef));
@@ -220,7 +221,7 @@ public class TypesJerseyResourceIT extends BaseResourceIT {
typesDef = new TypesDef(Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Collections.singletonList(classTypeDef));
String a1 = createType(AtlasType.toV1Json(typesDef)).get(0);
- classTypeDef = TypesUtil.createClassTypeDef("B" + randomString(),
null, Collections.<String>emptySet(), attr);
+ classTypeDef = TypesUtil.createClassTypeDef("B" + randomString(),
null, Collections.<String>emptySet(), attr1);
typesDef = new TypesDef(Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Collections.singletonList(classTypeDef));
String b = createType(AtlasType.toV1Json(typesDef)).get(0);