private Group processGroup(LdapContext ctx, Attributes a, Set<String> membersToIgnore) throws NamingException {
        XMPPServer server = XMPPServer.getInstance();
        String serverName = server.getServerInfo().getXMPPDomain();
        // Build `3 groups.
        // group 1: uid=
        // group 2: rest of the text until first comma
        // group 3: rest of the text
        Pattern pattern =
                Pattern.compile("(?i)(^" + manager.getUsernameField() + "=)([^,]+)(.+)");

        // We have to process Active Directory differently.
        boolean isAD = manager.getUsernameField().equals("sAMAccountName");
        String[] returningAttributes = isAD ? new String[] { "distinguishedName", manager.getUsernameField() } : new String[] { manager.getUsernameField() };

        SearchControls searchControls = new SearchControls();
        searchControls.setReturningAttributes(returningAttributes);
        // See if recursive searching is enabled. Otherwise, only search one level.
        if (manager.isSubTreeSearch()) {
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        }
        else {
            searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
        }

        String name;
        String description;
        try {
            name = ((String)((a.get(manager.getGroupNameField())).get()));
        }
        catch (Exception e) {
            name = "";
        }
        try {
            description = ((String)((a.get(manager.getGroupDescriptionField())).get()));
        }
        catch (Exception e) {
            description = "";
        }
        Set<JID> members = new TreeSet<>();
        Attribute memberField = a.get(manager.getGroupMemberField());

        Log.debug("Loading members of group: {}", name);

        if (memberField==null&&PROCESSBIGGROUPS.getValue())
        {
            NamingEnumeration<? extends Attribute> i = a.getAll();

            while (i.hasMore())
            {
                Attribute attribute = i.next();
                String key = attribute.getID().toLowerCase();
                if (key.startsWith(manager.getGroupMemberField()))
                {
                    memberField=attribute;
                    break;
                }
            }
        }

        if (memberField != null) {
            NamingEnumeration<?> ne = memberField.getAll();
            while (ne.hasMore()) {
                String username = (String) ne.next();
                LdapName userDN = null;
                // If not posix mode, each group member is stored as a full DN.
                if (!manager.isPosixMode()) {
                    try {
                        // Try to find the username with a regex pattern match.
                        Matcher matcher = pattern.matcher(username);
                        if (matcher.matches() && matcher.groupCount() == 3) {
                            // The username is in the DN, no additional search needed
                            username = matcher.group(2);
                        }
                        // The regex pattern match failed. This will happen if the
                        // the member DN's don't use the standard username field. For
                        // example, Active Directory has a username field of
                        // sAMAccountName, but stores group members as "CN=...".
                        else {
                            // Create an LDAP name with the full DN.
                            userDN = new LdapName(username);
                            // Turn the LDAP name into something we can use in a
                            // search by stripping off the comma.
                            StringBuilder userFilter = new StringBuilder();
                            userFilter.append("(&(");
                            userFilter.append(userDN.get(userDN.size() - 1));
                            userFilter.append(')');
                            userFilter.append(MessageFormat.format(manager.getSearchFilter(), "*"));
                            userFilter.append(')');
                            NamingEnumeration<SearchResult> usrAnswer = ctx.search("",
                                    userFilter.toString(), searchControls);
                            if (usrAnswer.hasMoreElements()) {
                                SearchResult searchResult = null;
                                // We may get multiple search results for the same user CN.
                                // Iterate through the entire set to find a matching distinguished name.
                                while(usrAnswer.hasMoreElements()) {
                                    searchResult = usrAnswer.nextElement();
                                    Attributes attrs = searchResult.getAttributes();
                                    if (isAD) {
                                        Attribute userdnAttr = attrs.get("distinguishedName");
                                        if (username.equals((String)userdnAttr.get())) {
                                            // Exact match found, use it.
                                            username = (String)attrs.get(manager.getUsernameField()).get();
                                            break;
                                        }
                                    }
                                    else {
                                        // No iteration occurs here, which is probably a bug.
                                        username = (String)attrs.get(manager.getUsernameField()).get();
                                        break;
                                    }
                                }
                            }
                            // Close the enumeration.
                            usrAnswer.close();
                        }
                    }
                    catch (Exception e) {
                        Log.error("An unexpected exception occurred while processing an LDAP group {}, while iterating over user {}", name, username, e);
                    }
                }
                // A search filter may have been defined in the LdapUserProvider.
                // Therefore, we have to try to load each user we found to see if
                // it passes the filter.
                try {
                    if (!membersToIgnore.contains(username)) {
                        JID userJID;
                        int position = username.indexOf("@" + serverName);
                        // Create JID of local user if JID does not match a component's JID
                        if (position == -1) {
                            // In order to lookup a username from the manager, the username
                            // must be a properly escaped JID node.
                            String escapedUsername = JID.escapeNode(username);
                            // Check if escaped username is valid
                            userManager.getUser(escapedUsername);
                            // No exception, so the user must exist. Add the user as a group
                            // member using the escaped username.
                            userJID = server.createJID(escapedUsername, null);
                        }
                        else {
                            // This is a JID of a component or node of a server's component
                            String node = username.substring(0, position);
                            String escapedUsername = JID.escapeNode(node);
                            userJID = new JID(escapedUsername + "@" + serverName).asBareJID();
                        }
                        members.add(userJID);
                    }
                }
                catch (UserNotFoundException e) {
                    // not a user!
                    // maybe it is a group?
                    boolean isGroup = false;
                    if (manager.isFlattenNestedGroups()) {
                        if (manager.isPosixMode()) { // in posix mode, the DN has not been set...
                            // Look up the userDN using the UID
                            String userDNStr = manager.retrieveSingle(null,
                                "(" + manager.getUsernameField()
                                    + "=" + LdapManager.sanitizeSearchFilter(username) + ")",
                                true);
                            if (userDNStr != null)
                                userDN = new LdapName(userDNStr);
                        } else if (userDN == null) {
                            // Create an LDAP name with the full DN.
                            userDN = new LdapName(username);
                        }
                        if (userDN != null && manager.isGroupDN(userDN)) {
                            isGroup = true;
                            if (!membersToIgnore.contains(userDN.toString())
                                && !membersToIgnore.contains(username)) {
                                // prevent endless adding of cyclic referenced groups
                                membersToIgnore.add(username);
                                membersToIgnore.add(userDN.toString());
                                // it's a sub group not already added, so add its members
                                Log.debug("Adding members of sub-group: {}", userDN);
                                Group subGroup = getGroupByDN(userDN, membersToIgnore);
                                members.addAll(subGroup.getMembers());
                            }
                        }
                    }
                    if (!isGroup) {
                        // We can safely ignore this error. It likely means that
                        // the user didn't pass the search filter that's defined.
                        // So, we want to simply ignore the user as a group member.
                        if (manager.isDebugEnabled()) {
                            Log.debug("LdapGroupProvider: User not found: " + username);
                        }
                    }
                }
            }
            // Close the enumeration.
            ne.close();
        }
        if (manager.isDebugEnabled()) {
            Log.debug("LdapGroupProvider: Adding group \"" + name + "\" with " + members.size() +
                    " members.");
        }
        Collection<JID> admins = Collections.emptyList();
        return new Group(name, description, members, admins);
    }
Reads the group with the given DN

@param groupDN         the absolute DN of the group
@param membersToIgnore A mutable set of DNs and/or UIDs (for Posix mode) to ignore. This set will be
                       filled with visited DNs. If flatten of hierarchies of groups is active
                       ({@link LdapManager#isFlattenNestedGroups()}, this will prevent endless loops
                       for cyclic hierarchies.
@return A group (never null)
@throws NamingException When a group can't be read from LDAP.
xmppserver/src/main/java/org/jivesoftware/openfire/ldap/LdapGroupProvider.java