class AmbariLdapDataPopulator {

  protected void refreshGroupMembers(LdapBatchDto batchInfo, LdapGroupDto group, Map<String, User> internalUsers,
                                     Map<String, Group> internalGroupsMap, Set<String> groupMemberAttributes, boolean recursive)
      throws AmbariException {
    Set<LdapUserDto> externalMembers = new HashSet<>();

    if (groupMemberAttributes == null) {
      groupMemberAttributes = new HashSet<>();
    }

    for (String memberAttributeValue : group.getMemberAttributes()) {
      LdapUserDto groupMember = getLdapUserByMemberAttr(memberAttributeValue);
      if (groupMember != null) {
        externalMembers.add(groupMember);
      } else {
        // if we haven't already processed this group
        if (recursive && !groupMemberAttributes.contains(memberAttributeValue)) {
          // if the member is another group then add all of its members
          LdapGroupDto subGroup = getLdapGroupByMemberAttr(memberAttributeValue);
          if (subGroup != null) {
            groupMemberAttributes.add(memberAttributeValue);
            addLdapGroup(batchInfo, internalGroupsMap, subGroup);
            refreshGroupMembers(batchInfo, subGroup, internalUsers, internalGroupsMap, groupMemberAttributes, true);
          }
        }
      }
    }
    String groupName = group.getGroupName();
    final Map<String, User> internalMembers = getInternalMembers(groupName);
    for (LdapUserDto externalMember : externalMembers) {
      String userName = externalMember.getUserName();
      if (internalUsers.containsKey(userName)) {
        final User user = internalUsers.get(userName);
        if (user == null) {
          // user is fresh and is already added to batch info
          if (!internalMembers.containsKey(userName)) {
            batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember.getUserName()));
          }
          continue;
        }
        if (!user.isLdapUser()) {
          if (LdapUsernameCollisionHandlingBehavior.SKIP == getConfiguration().syncCollisionHandlingBehavior()) {
            // existing user can not be converted to ldap user, so skip it
            LOG.info("User '{}' skipped because it is local user", userName);
            batchInfo.getUsersSkipped().add(externalMember);
            continue; // and remove from group
          } else {
            batchInfo.getUsersToBecomeLdap().add(externalMember);
          }
        }
        if (!internalMembers.containsKey(userName)) {
          batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember.getUserName()));
        }
        internalMembers.remove(userName);
      } else {
        batchInfo.getUsersToBeCreated().add(externalMember);
        batchInfo.getMembershipToAdd().add(new LdapUserGroupMemberDto(groupName, externalMember.getUserName()));
      }
    }
    for (Entry<String, User> userToBeUnsynced : internalMembers.entrySet()) {
      final User user = userToBeUnsynced.getValue();
      batchInfo.getMembershipToRemove().add(new LdapUserGroupMemberDto(groupName, user.getUserName()));
    }
  }

  @Inject public  AmbariLdapDataPopulator(Provider<AmbariLdapConfiguration> configurationProvider, Users users);

}