diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasBusinessMetadataDefStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasBusinessMetadataDefStoreV2.java index 5511935f918..5d793fdbc31 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasBusinessMetadataDefStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasBusinessMetadataDefStoreV2.java @@ -31,10 +31,14 @@ import org.apache.atlas.model.typedef.AtlasBusinessMetadataDef; import org.apache.atlas.model.typedef.AtlasStructDef; import org.apache.atlas.repository.Constants; +import org.apache.atlas.repository.graphdb.AtlasGraph; +import org.apache.atlas.repository.graphdb.AtlasGraphQuery; import org.apache.atlas.repository.graphdb.AtlasVertex; import org.apache.atlas.type.AtlasBusinessMetadataType; import org.apache.atlas.type.AtlasStructType; import org.apache.atlas.type.AtlasType; +import org.apache.atlas.type.AtlasEntityType; +import org.apache.atlas.type.AtlasArrayType; import org.apache.atlas.type.AtlasTypeRegistry; import org.apache.atlas.typesystem.types.DataTypes; import org.apache.atlas.utils.AtlasJson; @@ -50,6 +54,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.HashSet; import static org.apache.atlas.model.typedef.AtlasBusinessMetadataDef.ATTR_OPTION_APPLICABLE_ENTITY_TYPES; @@ -58,11 +63,14 @@ public class AtlasBusinessMetadataDefStoreV2 extends AtlasAbstractDefStoreV2 attributeDefs = businessMetadataDef.getAttributeDefs(); + if (businessMetadataDef == null || CollectionUtils.isEmpty(businessMetadataDef.getAttributeDefs())) { + return; + } - for (AtlasStructDef.AtlasAttributeDef attributeDef : attributeDefs) { - String qualifiedName = AtlasStructType.AtlasAttribute.getQualifiedAttributeName(businessMetadataDef, attributeDef.getName()); - String vertexPropertyName = AtlasStructType.AtlasAttribute.generateVertexPropertyName(businessMetadataDef, attributeDef, qualifiedName); - Set applicableTypes = AtlasJson.fromJson(attributeDef.getOption(AtlasBusinessMetadataDef.ATTR_OPTION_APPLICABLE_ENTITY_TYPES), Set.class); + for (AtlasStructDef.AtlasAttributeDef attributeDef : businessMetadataDef.getAttributeDefs()) { + validateAttributeReferences(businessMetadataDef, attributeDef); + } + } - if (CollectionUtils.isNotEmpty(applicableTypes) && isBusinessAttributePresent(vertexPropertyName, applicableTypes)) { - throw new AtlasBaseException(AtlasErrorCode.TYPE_HAS_REFERENCES, typeName); - } - } + private void validateAttributeReferences(AtlasBusinessMetadataDef bmDef, AtlasStructDef.AtlasAttributeDef attributeDef) throws AtlasBaseException { + String applicableTypesStr = attributeDef.getOption(ATTR_OPTION_APPLICABLE_ENTITY_TYPES); + Set applicableTypes = StringUtils.isBlank(applicableTypesStr) ? null : AtlasJson.fromJson(applicableTypesStr, Set.class); + + if (CollectionUtils.isEmpty(applicableTypes)) { + return; + } + + Set allApplicableTypes = getApplicableTypesWithSubTypes(applicableTypes); + String qualifiedName = AtlasStructType.AtlasAttribute.getQualifiedAttributeName(bmDef, attributeDef.getName()); + String vertexPropertyName = AtlasStructType.AtlasAttribute.generateVertexPropertyName(bmDef, attributeDef, qualifiedName); + + boolean isPresent; + long startTime = System.currentTimeMillis(); + + if (isArrayAttribute(attributeDef)) { + isPresent = isBusinessAttributePresentInGraph(vertexPropertyName, allApplicableTypes); + } else { + isPresent = isBusinessAttributePresent(qualifiedName, allApplicableTypes); + } + + if (LOG.isDebugEnabled()) { + LOG.info("Reference check for attribute {} took {} ms. Found: {}", + attributeDef.getName(), (System.currentTimeMillis() - startTime), isPresent); + } + + if (isPresent) { + throw new AtlasBaseException(AtlasErrorCode.TYPE_HAS_REFERENCES, bmDef.getName()); } } private boolean isBusinessAttributePresent(String attrName, Set applicableTypes) throws AtlasBaseException { SearchParameters.FilterCriteria criteria = new SearchParameters.FilterCriteria(); - criteria.setAttributeName(attrName); criteria.setOperator(SearchParameters.Operator.NOT_EMPTY); SearchParameters.FilterCriteria entityFilters = new SearchParameters.FilterCriteria(); - entityFilters.setCondition(SearchParameters.FilterCriteria.Condition.OR); entityFilters.setCriterion(Collections.singletonList(criteria)); SearchParameters searchParameters = new SearchParameters(); - searchParameters.setTypeName(String.join(SearchContext.TYPENAME_DELIMITER, applicableTypes)); - searchParameters.setExcludeDeletedEntities(true); + searchParameters.setExcludeDeletedEntities(false); searchParameters.setIncludeSubClassifications(false); searchParameters.setEntityFilters(entityFilters); - searchParameters.setAttributes(Collections.singleton(attrName)); - searchParameters.setOffset(0); searchParameters.setLimit(1); AtlasSearchResult atlasSearchResult = entityDiscoveryService.searchWithParameters(searchParameters); + return atlasSearchResult != null && CollectionUtils.isNotEmpty(atlasSearchResult.getEntities()); + } + + private boolean isBusinessAttributePresentInGraph(String vertexPropertyName, Set allApplicableTypes) { + if (graph == null || CollectionUtils.isEmpty(allApplicableTypes)) { + return false; + } + + try { + Iterable vertices = graph.query() + .has(vertexPropertyName, AtlasGraphQuery.ComparisionOperator.NOT_EQUAL, (Object) null) + .vertices(); - return CollectionUtils.isNotEmpty(atlasSearchResult.getEntities()); + if (vertices != null) { + Iterator iterator = vertices.iterator(); + if (iterator.hasNext()) { + if (LOG.isDebugEnabled()) { + LOG.info("Found ARRAY BM reference for property {}",vertexPropertyName); + } + return true; + } + } + } catch (Exception e) { + LOG.error("Error occurred while querying graph for references of property: {}", vertexPropertyName, e); + return true; + } + return false; + } + + private boolean isArrayAttribute(AtlasStructDef.AtlasAttributeDef attrDef) throws AtlasBaseException { + AtlasType type = typeRegistry.getType(attrDef.getTypeName()); + return type instanceof AtlasArrayType; + } + + private Set getApplicableTypesWithSubTypes(Set applicableTypes) throws AtlasBaseException { + Set allTypes = new HashSet<>(); + + for (String typeName : applicableTypes) { + AtlasType type = typeRegistry.getType(typeName); + + if (type instanceof AtlasEntityType) { + AtlasEntityType entityType = (AtlasEntityType) type; + allTypes.add(entityType.getTypeName()); + allTypes.addAll(entityType.getAllSubTypes()); + } else { + allTypes.add(typeName); + } + } + return allTypes; } -} +} \ No newline at end of file diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasTypeDefGraphStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasTypeDefGraphStoreV2.java index 57146521ab8..2ae2ec10164 100644 --- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasTypeDefGraphStoreV2.java +++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasTypeDefGraphStoreV2.java @@ -177,7 +177,7 @@ protected AtlasDefStore getRelationshipDefStore(AtlasTypeR @Override protected AtlasDefStore getBusinessMetadataDefStore(AtlasTypeRegistry typeRegistry) { - return new AtlasBusinessMetadataDefStoreV2(this, typeRegistry, this.entityDiscoveryService); + return new AtlasBusinessMetadataDefStoreV2(this, typeRegistry, this.entityDiscoveryService, this.atlasGraph); } @Override