@@ -266,8 +266,14 @@ public AtlasBusinessMetadataDef updateByGuid(String guid, AtlasBusinessMetadataD
266266 return ret ;
267267 }
268268
269+ @ Override
269270 public AtlasVertex preDeleteByName (String name ) throws AtlasBaseException {
270- LOG .debug ("==> AtlasBusinessMetadataDefStoreV2.preDeleteByName({})" , name );
271+ return preDeleteByName (name , false );
272+ }
273+
274+ @ Override
275+ public AtlasVertex preDeleteByName (String name , boolean forceDelete ) throws AtlasBaseException {
276+ LOG .debug ("==> AtlasBusinessMetadataDefStoreV2.preDeleteByName({}, {})" , name , forceDelete );
271277
272278 AtlasBusinessMetadataDef existingDef = typeRegistry .getBusinessMetadataDefByName (name );
273279
@@ -279,15 +285,29 @@ public AtlasVertex preDeleteByName(String name) throws AtlasBaseException {
279285 throw new AtlasBaseException (AtlasErrorCode .TYPE_NAME_NOT_FOUND , name );
280286 }
281287
282- checkBusinessMetadataRef (existingDef .getName ());
288+ if (!forceDelete ) {
289+ boolean hasIndexableAttribute = hasIndexableAttribute (existingDef );
290+
291+ if (!hasIndexableAttribute ) {
292+ LOG .warn ("Deletion blocked for non-indexable Business Metadata '{}' without force-delete flag" , name );
293+ throw new AtlasBaseException (AtlasErrorCode .NON_INDEXABLE_BM_DELETE_NOT_ALLOWED , name );
294+ }
295+ checkBusinessMetadataRef (existingDef .getName ());
296+ }
283297
284- LOG .debug ("<== AtlasBusinessMetadataDefStoreV2.preDeleteByName({}): {}" , name , ret );
298+ LOG .debug ("<== AtlasBusinessMetadataDefStoreV2.preDeleteByName({}, {} ): {}" , name , forceDelete , ret );
285299
286300 return ret ;
287301 }
288302
303+ @ Override
289304 public AtlasVertex preDeleteByGuid (String guid ) throws AtlasBaseException {
290- LOG .debug ("==> AtlasBusinessMetadataDefStoreV2.preDeleteByGuid({})" , guid );
305+ return preDeleteByGuid (guid , false );
306+ }
307+
308+ @ Override
309+ public AtlasVertex preDeleteByGuid (String guid , boolean forceDelete ) throws AtlasBaseException {
310+ LOG .debug ("==> AtlasBusinessMetadataDefStoreV2.preDeleteByGuid({}, {})" , guid , forceDelete );
291311
292312 AtlasBusinessMetadataDef existingDef = typeRegistry .getBusinessMetadataDefByGuid (guid );
293313
@@ -299,15 +319,35 @@ public AtlasVertex preDeleteByGuid(String guid) throws AtlasBaseException {
299319 throw new AtlasBaseException (AtlasErrorCode .TYPE_GUID_NOT_FOUND , guid );
300320 }
301321
302- if (existingDef != null ) {
322+ if (existingDef != null && !forceDelete ) {
323+ boolean hasIndexableAttribute = hasIndexableAttribute (existingDef );
324+
325+ if (!hasIndexableAttribute ) {
326+ LOG .warn ("Deletion blocked for non-indexable Business Metadata '{}' without force-delete flag" , existingDef .getName ());
327+ throw new AtlasBaseException (AtlasErrorCode .NON_INDEXABLE_BM_DELETE_NOT_ALLOWED , existingDef .getName ());
328+ }
303329 checkBusinessMetadataRef (existingDef .getName ());
304330 }
305331
306- LOG .debug ("<== AtlasBusinessMetadataDefStoreV2.preDeleteByGuid({}): ret={}" , guid , ret );
332+ LOG .debug ("<== AtlasBusinessMetadataDefStoreV2.preDeleteByGuid({}, {} ): ret={}" , guid , forceDelete , ret );
307333
308334 return ret ;
309335 }
310336
337+ private boolean hasIndexableAttribute (AtlasBusinessMetadataDef bmDef ) {
338+ if (bmDef == null || CollectionUtils .isEmpty (bmDef .getAttributeDefs ())) {
339+ return false ;
340+ }
341+
342+ for (AtlasStructDef .AtlasAttributeDef attributeDef : bmDef .getAttributeDefs ()) {
343+ if (attributeDef .getIsIndexable ()) {
344+ return true ;
345+ }
346+ }
347+
348+ return false ;
349+ }
350+
311351 @ Override
312352 public void validateType (AtlasBaseTypeDef typeDef ) throws AtlasBaseException {
313353 super .validateType (typeDef );
@@ -392,14 +432,9 @@ private void validateAttributeReferences(AtlasBusinessMetadataDef bmDef, AtlasSt
392432 String qualifiedName = AtlasStructType .AtlasAttribute .getQualifiedAttributeName (bmDef , attributeDef .getName ());
393433 String vertexPropertyName = AtlasStructType .AtlasAttribute .generateVertexPropertyName (bmDef , attributeDef , qualifiedName );
394434
395- boolean isPresent ;
396435 long startTime = System .currentTimeMillis ();
397436
398- if (isArrayAttribute (attributeDef )) {
399- isPresent = isBusinessAttributePresentInGraph (vertexPropertyName , allApplicableTypes );
400- } else {
401- isPresent = isBusinessAttributePresent (qualifiedName , allApplicableTypes );
402- }
437+ boolean isPresent = isBusinessAttributePresentInGraph (vertexPropertyName , allApplicableTypes );
403438
404439 if (LOG .isDebugEnabled ()) {
405440 LOG .info ("Reference check for attribute {} took {} ms. Found: {}" ,
@@ -411,44 +446,34 @@ private void validateAttributeReferences(AtlasBusinessMetadataDef bmDef, AtlasSt
411446 }
412447 }
413448
414- private boolean isBusinessAttributePresent (String attrName , Set <String > applicableTypes ) throws AtlasBaseException {
415- SearchParameters .FilterCriteria criteria = new SearchParameters .FilterCriteria ();
416- criteria .setAttributeName (attrName );
417- criteria .setOperator (SearchParameters .Operator .NOT_EMPTY );
418-
419- SearchParameters .FilterCriteria entityFilters = new SearchParameters .FilterCriteria ();
420- entityFilters .setCondition (SearchParameters .FilterCriteria .Condition .OR );
421- entityFilters .setCriterion (Collections .singletonList (criteria ));
422-
423- SearchParameters searchParameters = new SearchParameters ();
424- searchParameters .setTypeName (String .join (SearchContext .TYPENAME_DELIMITER , applicableTypes ));
425- searchParameters .setExcludeDeletedEntities (false );
426- searchParameters .setIncludeSubClassifications (false );
427- searchParameters .setEntityFilters (entityFilters );
428- searchParameters .setLimit (1 );
429-
430- AtlasSearchResult atlasSearchResult = entityDiscoveryService .searchWithParameters (searchParameters );
431- return atlasSearchResult != null && CollectionUtils .isNotEmpty (atlasSearchResult .getEntities ());
432- }
433449
434450 private boolean isBusinessAttributePresentInGraph (String vertexPropertyName , Set <String > allApplicableTypes ) {
435451 if (graph == null || CollectionUtils .isEmpty (allApplicableTypes )) {
436452 return false ;
437453 }
438454
439455 try {
440- Iterable <AtlasVertex > vertices = graph .query ()
456+ List <String > typesList = new ArrayList <>(allApplicableTypes );
457+
458+ // 1. To Check if the BM property exists on a vertex where the direct type matches
459+ Iterable <AtlasVertex > verticesDirect = graph .query ()
441460 .has (vertexPropertyName , AtlasGraphQuery .ComparisionOperator .NOT_EQUAL , (Object ) null )
461+ .in (Constants .ENTITY_TYPE_PROPERTY_KEY , typesList )
442462 .vertices ();
443463
444- if (vertices != null ) {
445- Iterator <AtlasVertex > iterator = vertices .iterator ();
446- if (iterator .hasNext ()) {
447- if (LOG .isDebugEnabled ()) {
448- LOG .info ("Found ARRAY BM reference for property {}" ,vertexPropertyName );
449- }
450- return true ;
451- }
464+ if (verticesDirect != null && verticesDirect .iterator ().hasNext ()) {
465+ return true ;
466+ }
467+
468+ // 2. To Check if the BM property exists on a vertex where it inherits from one of parent Types
469+ // This is crucial for Case 6 (Parent -> Child)
470+ Iterable <AtlasVertex > verticesInherited = graph .query ()
471+ .has (vertexPropertyName , AtlasGraphQuery .ComparisionOperator .NOT_EQUAL , (Object ) null )
472+ .in (Constants .SUPER_TYPES_PROPERTY_KEY , typesList )
473+ .vertices ();
474+
475+ if (verticesInherited != null && verticesInherited .iterator ().hasNext ()) {
476+ return true ;
452477 }
453478 } catch (Exception e ) {
454479 LOG .error ("Error occurred while querying graph for references of property: {}" , vertexPropertyName , e );
@@ -457,11 +482,6 @@ private boolean isBusinessAttributePresentInGraph(String vertexPropertyName, Set
457482 return false ;
458483 }
459484
460- private boolean isArrayAttribute (AtlasStructDef .AtlasAttributeDef attrDef ) throws AtlasBaseException {
461- AtlasType type = typeRegistry .getType (attrDef .getTypeName ());
462- return type instanceof AtlasArrayType ;
463- }
464-
465485 private Set <String > getApplicableTypesWithSubTypes (Set <String > applicableTypes ) throws AtlasBaseException {
466486 Set <String > allTypes = new HashSet <>();
467487
0 commit comments