/**
   * Deletes the specified entity vertices. Deletes any traits, composite entities, and structs
   * owned by each entity. Also deletes all the references from/to the entity.
   *
   * @param instanceVertices
   * @throws AtlasException
   */
  public void deleteEntities(List<AtlasVertex> instanceVertices) throws AtlasException {
    RequestContext requestContext = RequestContext.get();

    Set<AtlasVertex> deletionCandidateVertices = new HashSet<>();

    for (AtlasVertex instanceVertex : instanceVertices) {
      String guid = GraphHelper.getIdFromVertex(instanceVertex);
      Id.EntityState state = GraphHelper.getState(instanceVertex);
      if (requestContext.getDeletedEntityIds().contains(guid) || state == Id.EntityState.DELETED) {
        LOG.debug("Skipping deletion of {} as it is already deleted", guid);
        continue;
      }

      // Get GUIDs and vertices for all deletion candidates.
      Set<VertexInfo> compositeVertices = graphHelper.getCompositeVertices(instanceVertex);

      // Record all deletion candidate GUIDs in RequestContext
      // and gather deletion candidate vertices.
      for (VertexInfo vertexInfo : compositeVertices) {
        requestContext.recordEntityDelete(vertexInfo.getGuid(), vertexInfo.getTypeName());
        deletionCandidateVertices.add(vertexInfo.getVertex());
      }
    }

    // Delete traits and vertices.
    for (AtlasVertex deletionCandidateVertex : deletionCandidateVertices) {
      deleteAllTraits(deletionCandidateVertex);
      deleteTypeVertex(deletionCandidateVertex, false);
    }
  }
  /**
   * Deletes the entity vertex - deletes the traits and all the references
   *
   * @param instanceVertex
   * @throws AtlasException
   */
  public void deleteEntity(Vertex instanceVertex) throws AtlasException {
    RequestContext requestContext = RequestContext.get();
    String guid = GraphHelper.getIdFromVertex(instanceVertex);
    Id.EntityState state = GraphHelper.getState(instanceVertex);
    if (requestContext.getDeletedEntityIds().contains(guid) || state == Id.EntityState.DELETED) {
      LOG.debug("Skipping deleting {} as its already deleted", guid);
      return;
    }
    String typeName = GraphHelper.getTypeName(instanceVertex);
    requestContext.recordEntityDelete(guid, typeName);

    deleteAllTraits(instanceVertex);

    deleteTypeVertex(instanceVertex, false);
  }
  /**
   * Deletes a type vertex - can be entity(class type) or just vertex(struct/trait type)
   *
   * @param instanceVertex
   * @param typeCategory
   * @throws AtlasException
   */
  protected void deleteTypeVertex(
      Vertex instanceVertex, DataTypes.TypeCategory typeCategory, boolean force)
      throws AtlasException {
    switch (typeCategory) {
      case STRUCT:
      case TRAIT:
        deleteTypeVertex(instanceVertex, force);
        break;

      case CLASS:
        deleteEntity(instanceVertex);
        break;

      default:
        throw new IllegalStateException("Type category " + typeCategory + " not handled");
    }
  }
  /**
   * Force delete is used to remove struct/trait in case of entity updates
   *
   * @param edge
   * @param typeCategory
   * @param isComposite
   * @param forceDeleteStructTrait
   * @return returns true if the edge reference is hard deleted
   * @throws AtlasException
   */
  public boolean deleteEdgeReference(
      AtlasEdge edge,
      DataTypes.TypeCategory typeCategory,
      boolean isComposite,
      boolean forceDeleteStructTrait)
      throws AtlasException {
    LOG.debug("Deleting {}", string(edge));
    boolean forceDelete =
        (typeCategory == DataTypes.TypeCategory.STRUCT
                || typeCategory == DataTypes.TypeCategory.TRAIT)
            ? forceDeleteStructTrait
            : false;
    if (typeCategory == DataTypes.TypeCategory.STRUCT
        || typeCategory == DataTypes.TypeCategory.TRAIT
        || (typeCategory == DataTypes.TypeCategory.CLASS && isComposite)) {
      // If the vertex is of type struct/trait, delete the edge and then the reference vertex as the
      // vertex is not shared by any other entities.
      // If the vertex is of type class, and its composite attribute, this reference vertex'
      // lifecycle is controlled
      // through this delete, hence delete the edge and the reference vertex.
      AtlasVertex vertexForDelete = edge.getInVertex();

      // If deleting the edge and then the in vertex, reverse attribute shouldn't be updated
      deleteEdge(edge, false, forceDelete);
      deleteTypeVertex(vertexForDelete, typeCategory, forceDelete);
    } else {
      // If the vertex is of type class, and its not a composite attributes, the reference
      // AtlasVertex' lifecycle is not controlled
      // through this delete. Hence just remove the reference edge. Leave the reference AtlasVertex
      // as is

      // If deleting just the edge, reverse attribute should be updated for any references
      // For example, for the department type system, if the person's manager edge is deleted,
      // subordinates of manager should be updated
      deleteEdge(edge, true, false);
    }
    return !softDelete || forceDelete;
  }